forked from objectionary/opeo-maven-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(objectionary#284): add first implementation for If node
- Loading branch information
1 parent
f95df4c
commit 45b07f9
Showing
4 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
* The MIT License (MIT) | ||
* | ||
* Copyright (c) 2016-2023 Objectionary.com | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included | ||
* in all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
*/ | ||
package org.eolang.opeo.ast; | ||
|
||
import java.util.List; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.ToString; | ||
import org.eolang.jeo.representation.xmir.XmlNode; | ||
import org.objectweb.asm.Opcodes; | ||
import org.xembly.Directive; | ||
import org.xembly.Directives; | ||
|
||
/** | ||
* If ast node. | ||
* @since 0.2 | ||
*/ | ||
@ToString | ||
@EqualsAndHashCode | ||
public final class If implements AstNode { | ||
|
||
/** | ||
* First value to compare. | ||
*/ | ||
private final AstNode first; | ||
|
||
/** | ||
* Second value to compare. | ||
*/ | ||
private final AstNode second; | ||
|
||
/** | ||
* Where to jump if the comparison is true. | ||
*/ | ||
private final Label target; | ||
|
||
/** | ||
* Constructor. | ||
* @param node XMIR node. | ||
*/ | ||
public If(final XmlNode node, Function<XmlNode, AstNode> search) { | ||
this(If.xfirst(node, search), If.xsecond(node, search), If.xtarget(node)); | ||
} | ||
|
||
/** | ||
* Constructor. | ||
* @param first First value. | ||
* @param second Second value. | ||
* @param target Target label. | ||
*/ | ||
public If( | ||
final AstNode first, | ||
final AstNode second, | ||
final Label target | ||
) { | ||
this.first = first; | ||
this.second = second; | ||
this.target = target; | ||
} | ||
|
||
@Override | ||
public List<AstNode> opcodes() { | ||
return Stream.concat( | ||
Stream.concat( | ||
this.first.opcodes().stream(), | ||
this.second.opcodes().stream() | ||
), | ||
Stream.of(new Opcode(Opcodes.IF_ICMPGT, this.target)) | ||
).collect(Collectors.toList()); | ||
} | ||
|
||
@Override | ||
public Iterable<Directive> toXmir() { | ||
return new Directives() | ||
.add("o").attr("base", ".if") | ||
.add("o").attr("base", ".gt") | ||
.append(this.first.toXmir()) | ||
.append(this.second.toXmir()) | ||
.up() | ||
.append(this.target.toXmir()) | ||
.add("o").attr("base", "nop").up() | ||
.up(); | ||
} | ||
|
||
/** | ||
* Extracts the first value. | ||
* @param node XMIR node where to extract the value. | ||
* @return Value. | ||
*/ | ||
private static AstNode xfirst(final XmlNode node, Function<XmlNode, AstNode> search) { | ||
return search.apply(node.child("base", ".gt").firstChild()); | ||
} | ||
|
||
/** | ||
* Extracts the second value. | ||
* @param node XMIR node where to extract the value. | ||
* @return Value. | ||
*/ | ||
private static AstNode xsecond(final XmlNode node, Function<XmlNode, AstNode> search) { | ||
final List<XmlNode> children = node.child("base", ".gt").children() | ||
.collect(Collectors.toList()); | ||
return search.apply(children.get(children.size() - 1)); | ||
|
||
} | ||
|
||
/** | ||
* Extracts the target label. | ||
* @param node XMIR node where to extract the label. | ||
* @return Label. | ||
*/ | ||
private static Label xtarget(final XmlNode node) { | ||
return new Label(node.child("base", "label")); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
src/main/java/org/eolang/opeo/decompilation/handlers/IfHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,31 @@ | ||
package org.eolang.opeo.decompilation.handlers; | ||
|
||
import org.eolang.opeo.ast.AstNode; | ||
import org.eolang.opeo.ast.If; | ||
import org.eolang.opeo.ast.Label; | ||
import org.eolang.opeo.ast.Opcode; | ||
import org.eolang.opeo.decompilation.DecompilerState; | ||
import org.eolang.opeo.decompilation.InstructionHandler; | ||
import org.eolang.opeo.decompilation.OperandStack; | ||
import org.objectweb.asm.Opcodes; | ||
|
||
/** | ||
* If instruction handler. | ||
* [value1, value2] → [] | ||
* If value1 is greater than value2, branch to instruction at branchoffset | ||
* (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2) | ||
* @since 0.2 | ||
*/ | ||
public final class IfHandler implements InstructionHandler { | ||
@Override | ||
public void handle(final DecompilerState state) { | ||
if (state.instruction().opcode() == Opcodes.IF_ICMPGT) { | ||
final OperandStack stack = state.stack(); | ||
final AstNode first = stack.pop(); | ||
final AstNode second = stack.pop(); | ||
final Label operand = (Label) state.operand(0); | ||
stack.push(new If(first, second, operand)); | ||
|
||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* The MIT License (MIT) | ||
* | ||
* Copyright (c) 2016-2023 Objectionary.com | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included | ||
* in all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
*/ | ||
package org.eolang.opeo.ast; | ||
|
||
import com.jcabi.xml.XMLDocument; | ||
import org.eolang.jeo.representation.xmir.XmlNode; | ||
import org.hamcrest.MatcherAssert; | ||
import org.hamcrest.Matchers; | ||
import org.junit.jupiter.api.Test; | ||
import org.objectweb.asm.Opcodes; | ||
import org.xembly.ImpossibleModificationException; | ||
import org.xembly.Xembler; | ||
|
||
/** | ||
* Test case for {@link If}. | ||
* @since 0.2 | ||
*/ | ||
class IfTest { | ||
|
||
/** | ||
* Xmir for the 'if' statement. | ||
*/ | ||
private static final String XMIR = String.join( | ||
"\n", | ||
"<?xml version='1.0' encoding='UTF-8'?>", | ||
"<o base='.if'>", | ||
" <o base='.gt'>", | ||
" <o base='int' data='bytes'>00 00 00 00 00 00 00 01</o>", | ||
" <o base='int' data='bytes'>00 00 00 00 00 00 00 02</o>", | ||
" </o>", | ||
" <o base='label' data='bytes'>C3 BF</o>", | ||
" <o base='nop'/>", | ||
"</o>", | ||
"" | ||
); | ||
|
||
@Test | ||
void convertsIfStatementToXmir() throws ImpossibleModificationException { | ||
MatcherAssert.assertThat( | ||
"Can convert 'if' statement to correct XMIR", | ||
new XMLDocument( | ||
new Xembler( | ||
new If( | ||
new Literal(1), new Literal(2), new Label("FF") | ||
).toXmir() | ||
).xml() | ||
), | ||
Matchers.equalTo(new XMLDocument(IfTest.XMIR)) | ||
); | ||
} | ||
|
||
@Test | ||
void createsIfStatementFromXmir() { | ||
MatcherAssert.assertThat( | ||
"Can create 'if' statement from XMIR", | ||
new If(new XmlNode(IfTest.XMIR), xml -> { | ||
final AstNode result; | ||
if (xml.text().contains("1")) { | ||
result = new Literal(1); | ||
} else { | ||
result = new Literal(2); | ||
} | ||
return result; | ||
}), | ||
Matchers.equalTo( | ||
new If( | ||
new Literal(1), | ||
new Literal(2), | ||
new Label("C3 BF") | ||
) | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void convertsToOpcodes() { | ||
final Label label = new Label("C3 BF"); | ||
MatcherAssert.assertThat( | ||
"Can convert 'if' statement to opcodes", | ||
new If( | ||
new Literal(1), | ||
new Literal(2), | ||
label | ||
).opcodes(), | ||
Matchers.hasItems( | ||
new Opcode(Opcodes.ICONST_1), | ||
new Opcode(Opcodes.ICONST_2), | ||
new Opcode(Opcodes.IF_ICMPGT, label) | ||
) | ||
); | ||
} | ||
} |