From 782a6f8231713ac0183041d422e17ab489fba4f3 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 28 Dec 2023 16:22:18 +0300 Subject: [PATCH 1/7] feat(#25): add test for InstanceField --- .../org/eolang/opeo/ast/InstanceField.java | 63 +++++++++++++++++++ .../opeo/vmachine/DecompilerMachine.java | 14 +++++ .../eolang/opeo/ast/InstanceFieldTest.java | 60 ++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 src/main/java/org/eolang/opeo/ast/InstanceField.java create mode 100644 src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java diff --git a/src/main/java/org/eolang/opeo/ast/InstanceField.java b/src/main/java/org/eolang/opeo/ast/InstanceField.java new file mode 100644 index 00000000..a14e7242 --- /dev/null +++ b/src/main/java/org/eolang/opeo/ast/InstanceField.java @@ -0,0 +1,63 @@ +/* + * 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 org.xembly.Directive; + +/** + * Access to a field. + * @since 0.1 + */ +public final class InstanceField implements AstNode { + + /** + * Object reference from which the field is accessed. + */ + private final AstNode source; + + /** + * Field name. + */ + private final String name; + + /** + * Constructor. + * @param source Object reference from which the field is accessed + * @param name Field name + */ + public InstanceField(final AstNode source, final String name) { + this.source = source; + this.name = name; + } + + @Override + public String print() { + return String.format("%s.%s", this.source.print(), this.name); + } + + @Override + public Iterable toXmir() { + return null; + } +} diff --git a/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java b/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java index 33f91068..c0498df3 100644 --- a/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java +++ b/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java @@ -108,6 +108,7 @@ public DecompilerMachine(final LocalVariables locals, final Map new MapEntry<>(Opcodes.BIPUSH, new BipushHandler()), new MapEntry<>(Opcodes.INVOKESPECIAL, new InvokespecialHandler()), new MapEntry<>(Opcodes.INVOKEVIRTUAL, new InvokevirtualHandler()), + new MapEntry<>(Opcodes.GETFIELD, new GetFieldHandler()), new MapEntry<>(Opcodes.LDC, new LdcHandler()), new MapEntry<>(Opcodes.POP, new PopHandler()), new MapEntry<>(Opcodes.RETURN, new ReturnHandler()) @@ -211,6 +212,19 @@ public void handle(final Instruction instruction) { } + /** + * Getfield instruction handler. + * @since 0.1 + */ + private class GetFieldHandler implements InstructionHandler { + + @Override + public void handle(final Instruction instruction) { + final String variable = (String) instruction.operand(1); + final AstNode ref = DecompilerMachine.this.stack.pop(); + } + } + /** * Dup instruction handler. * @since 0.1 diff --git a/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java b/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java new file mode 100644 index 00000000..68ac9dd8 --- /dev/null +++ b/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java @@ -0,0 +1,60 @@ +/* + * 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.matchers.XhtmlMatchers; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.xembly.ImpossibleModificationException; +import org.xembly.Xembler; + +/** + * Test case for {@link InstanceField}. + * @since 0.1 + */ +class InstanceFieldTest { + + @Test + void printsField() { + MatcherAssert.assertThat( + "We can't print a field access, actual result is wrong", + new InstanceField(new This(), "bar").print(), + Matchers.equalTo("this.bar") + ); + } + + @Test + void convertsToXmir() throws ImpossibleModificationException { + final String actual = new Xembler(new InstanceField(new This(), "bar").toXmir()).xml(); + MatcherAssert.assertThat( + String.format( + "Can't convert to a field access construct, actual result is : %n%s%n", + actual + ), + actual, + XhtmlMatchers.hasXPath("/o[@base='this']/a[@name='bar']") + ); + } +} From 4221920b452e9b7248aa21d43fc3fc7d1639a69e Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 28 Dec 2023 16:33:36 +0300 Subject: [PATCH 2/7] feat(#25): implement the field convertation --- .../java/org/eolang/opeo/ast/InstanceField.java | 7 ++++++- .../org/eolang/opeo/ast/InstanceFieldTest.java | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/eolang/opeo/ast/InstanceField.java b/src/main/java/org/eolang/opeo/ast/InstanceField.java index a14e7242..ccce23d4 100644 --- a/src/main/java/org/eolang/opeo/ast/InstanceField.java +++ b/src/main/java/org/eolang/opeo/ast/InstanceField.java @@ -24,6 +24,7 @@ package org.eolang.opeo.ast; import org.xembly.Directive; +import org.xembly.Directives; /** * Access to a field. @@ -58,6 +59,10 @@ public String print() { @Override public Iterable toXmir() { - return null; + return new Directives() + .append(this.source.toXmir()) + .add("o") + .attr("base", String.format(".%s", this.name)) + .up(); } } diff --git a/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java b/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java index 68ac9dd8..7aa3f3f9 100644 --- a/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java +++ b/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java @@ -27,6 +27,7 @@ import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import org.xembly.Directives; import org.xembly.ImpossibleModificationException; import org.xembly.Xembler; @@ -47,14 +48,23 @@ void printsField() { @Test void convertsToXmir() throws ImpossibleModificationException { - final String actual = new Xembler(new InstanceField(new This(), "bar").toXmir()).xml(); + final String actual = new Xembler( + new Directives() + .add("o") + .attr("name", "method") + .append(new InstanceField(new This(), "bar").toXmir()) + .up() + ).xml(); MatcherAssert.assertThat( String.format( "Can't convert to a field access construct, actual result is : %n%s%n", actual ), actual, - XhtmlMatchers.hasXPath("/o[@base='this']/a[@name='bar']") + XhtmlMatchers.hasXPaths( + "./o[@name='method']/o[@base='$']", + "./o[@name='method']/o[@base='.bar']" + ) ); } } From f941384ce5bd1d8ef6d3b782174b07f7096c255f Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 28 Dec 2023 16:41:04 +0300 Subject: [PATCH 3/7] feat(#25): fix the problem with GETFIELD handler implementation --- .../opeo/vmachine/DecompilerMachine.java | 9 +++++-- .../opeo/vmachine/DecompilerMachineTest.java | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java b/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java index c0498df3..71533f7b 100644 --- a/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java +++ b/src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java @@ -36,6 +36,7 @@ import org.eolang.opeo.ast.Add; import org.eolang.opeo.ast.AstNode; import org.eolang.opeo.ast.Constructor; +import org.eolang.opeo.ast.InstanceField; import org.eolang.opeo.ast.Invocation; import org.eolang.opeo.ast.Literal; import org.eolang.opeo.ast.Opcode; @@ -220,8 +221,12 @@ private class GetFieldHandler implements InstructionHandler { @Override public void handle(final Instruction instruction) { - final String variable = (String) instruction.operand(1); - final AstNode ref = DecompilerMachine.this.stack.pop(); + DecompilerMachine.this.stack.push( + new InstanceField( + DecompilerMachine.this.stack.pop(), + (String) instruction.operand(1) + ) + ); } } diff --git a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java index efa3e7e7..fae7cda5 100644 --- a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java +++ b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java @@ -213,4 +213,29 @@ void decompilesNestedInstanceCallWithArguments() { ) ); } + + /** + * Test decompilation of instance field access. + *

+ * {@code + * this.a + this.b; + * } + *

+ */ + @Test + void decompilesFieldAccess() { + MatcherAssert.assertThat( + "Can't decompile field access instructions for 'this.a + this.b;'", + new DecompilerMachine().decompile( + new OpcodeInstruction(Opcodes.ALOAD, 0), + new OpcodeInstruction(Opcodes.GETFIELD, "App", "a", "I"), + new OpcodeInstruction(Opcodes.ALOAD, 0), + new OpcodeInstruction(Opcodes.GETFIELD, "App", "b", "I"), + new OpcodeInstruction(Opcodes.IADD) + ), + Matchers.equalTo( + "(this.a) + (this.b)" + ) + ); + } } From e1accb7af3f7b3451b7d78f825575308c8e8ae6e Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 28 Dec 2023 17:25:29 +0300 Subject: [PATCH 4/7] feat(#25): add the example that shows the problem --- .../opeo/vmachine/DecompilerMachineTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java index fae7cda5..e6959ce4 100644 --- a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java +++ b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java @@ -238,4 +238,30 @@ void decompilesFieldAccess() { ) ); } + + /** + * Test decompilation of instance field access and method invocation. + *

+ * {@code + * this.a.intValue() + 1; + * } + *

+ */ + @Test + void decompilesFieldAccessAndMethodInvocation() { + MatcherAssert.assertThat( + "Can't decompile field access and method invocation instructions for 'this.a.intValue() + 1;'", + new DecompilerMachine().decompile( + new OpcodeInstruction(Opcodes.ALOAD, 0), + new OpcodeInstruction(Opcodes.GETFIELD, "App", "a", "Ljava/lang/Integer;"), + new OpcodeInstruction(Opcodes.ALOAD, 0), + new OpcodeInstruction(Opcodes.INVOKEVIRTUAL, "App", "intValue", "()I"), + new OpcodeInstruction(Opcodes.ICONST_1), + new OpcodeInstruction(Opcodes.IADD) + ), + Matchers.equalTo( + "((this.a).intValue) + (1)" + ) + ); + } } From 011efbf1c608cca8605b13ac74b5b6c7f6b63d88 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 28 Dec 2023 18:57:57 +0300 Subject: [PATCH 5/7] feat(#25): change the logic of InstanceField --- .../org/eolang/opeo/ast/InstanceField.java | 2 +- .../opeo/vmachine/DecompilerMachineTest.java | 37 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/eolang/opeo/ast/InstanceField.java b/src/main/java/org/eolang/opeo/ast/InstanceField.java index ccce23d4..11a37f1f 100644 --- a/src/main/java/org/eolang/opeo/ast/InstanceField.java +++ b/src/main/java/org/eolang/opeo/ast/InstanceField.java @@ -60,9 +60,9 @@ public String print() { @Override public Iterable toXmir() { return new Directives() - .append(this.source.toXmir()) .add("o") .attr("base", String.format(".%s", this.name)) + .append(this.source.toXmir()) .up(); } } diff --git a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java index e6959ce4..905254f7 100644 --- a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java +++ b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java @@ -23,11 +23,15 @@ */ package org.eolang.opeo.vmachine; +import org.cactoos.text.TextOf; +import org.eolang.opeo.Instruction; import org.eolang.opeo.OpcodeInstruction; +import org.eolang.parser.XMIR; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.objectweb.asm.Opcodes; +import org.xembly.Xembler; /** * Test case for {@link DecompilerMachine}. @@ -254,7 +258,6 @@ void decompilesFieldAccessAndMethodInvocation() { new DecompilerMachine().decompile( new OpcodeInstruction(Opcodes.ALOAD, 0), new OpcodeInstruction(Opcodes.GETFIELD, "App", "a", "Ljava/lang/Integer;"), - new OpcodeInstruction(Opcodes.ALOAD, 0), new OpcodeInstruction(Opcodes.INVOKEVIRTUAL, "App", "intValue", "()I"), new OpcodeInstruction(Opcodes.ICONST_1), new OpcodeInstruction(Opcodes.IADD) @@ -264,4 +267,36 @@ void decompilesFieldAccessAndMethodInvocation() { ) ); } + + @Test + void decompilesFieldAccessAndMethodInvocationToEo() { + final String xml = new Xembler( + new DecompilerMachine().decompileToXmir( + new OpcodeInstruction(Opcodes.ALOAD, 0), + new OpcodeInstruction(Opcodes.GETFIELD, "App", "a", "Ljava/lang/Integer;"), + new OpcodeInstruction(Opcodes.INVOKEVIRTUAL, "App", "intValue", "()I"), + new OpcodeInstruction(Opcodes.ICONST_1), + new OpcodeInstruction(Opcodes.IADD) + ) + ).xmlQuietly(); + MatcherAssert.assertThat( + String.format( + "Can't decompile field access and method invocation into EO for 'this.a.intValue() + 1;', received XML: %n%s%n", + xml + ), + new XMIR(new TextOf(xml)).toEO(), + Matchers.equalTo( + String.join( + "\n", + "tuple", + " $", + " .a", + " .intValue", + " .plus", + " 1", + "" + ) + ) + ); + } } From 57d4972981feeb51818fc755d2f99e8a179e9036 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 28 Dec 2023 19:03:51 +0300 Subject: [PATCH 6/7] feat(#25): repair integration tests --- .../java/org/eolang/opeo/ast/InstanceFieldTest.java | 5 +++-- src/test/resources/packs/simple_objects.yaml | 12 ++---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java b/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java index 7aa3f3f9..3b8d5681 100644 --- a/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java +++ b/src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java @@ -62,8 +62,9 @@ void convertsToXmir() throws ImpossibleModificationException { ), actual, XhtmlMatchers.hasXPaths( - "./o[@name='method']/o[@base='$']", - "./o[@name='method']/o[@base='.bar']" + "./o[@name='method']", + "./o[@name='method']/o[@base='.bar']", + "./o[@name='method']/o[@base='.bar']/o[@base='$']" ) ); } diff --git a/src/test/resources/packs/simple_objects.yaml b/src/test/resources/packs/simple_objects.yaml index e4620127..d4780bb4 100644 --- a/src/test/resources/packs/simple_objects.yaml +++ b/src/test/resources/packs/simple_objects.yaml @@ -118,11 +118,7 @@ eo: seq > @ tuple $ - opcode > GETFIELD - 180 - "com/example/A" - "x" - "I" + .x 2 opcode > IMUL 104 @@ -175,11 +171,7 @@ eo: seq > @ tuple $ - opcode > GETFIELD - 180 - "com/example/B" - "a" - "Lcom/example/A;" + .a .foo .plus 1 From a70955cbdeed716d23bc76c71d5bab45d1348aa3 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Thu, 28 Dec 2023 19:06:13 +0300 Subject: [PATCH 7/7] feat(#25): fix all the linters suggestions --- .../java/org/eolang/opeo/vmachine/DecompilerMachineTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java index 905254f7..263bbf28 100644 --- a/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java +++ b/src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java @@ -24,7 +24,6 @@ package org.eolang.opeo.vmachine; import org.cactoos.text.TextOf; -import org.eolang.opeo.Instruction; import org.eolang.opeo.OpcodeInstruction; import org.eolang.parser.XMIR; import org.hamcrest.MatcherAssert;