Skip to content

Commit

Permalink
Merge branch '__rultor'
Browse files Browse the repository at this point in the history
  • Loading branch information
rultor committed Dec 29, 2023
2 parents 44b3353 + a70955c commit 0c51a6f
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 10 deletions.
68 changes: 68 additions & 0 deletions src/main/java/org/eolang/opeo/ast/InstanceField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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;
import org.xembly.Directives;

/**
* 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<Directive> toXmir() {
return new Directives()
.add("o")
.attr("base", String.format(".%s", this.name))
.append(this.source.toXmir())
.up();
}
}
19 changes: 19 additions & 0 deletions src/main/java/org/eolang/opeo/vmachine/DecompilerMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -108,6 +109,7 @@ public DecompilerMachine(final LocalVariables locals, final Map<String, String>
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())
Expand Down Expand Up @@ -211,6 +213,23 @@ public void handle(final Instruction instruction) {

}

/**
* Getfield instruction handler.
* @since 0.1
*/
private class GetFieldHandler implements InstructionHandler {

@Override
public void handle(final Instruction instruction) {
DecompilerMachine.this.stack.push(
new InstanceField(
DecompilerMachine.this.stack.pop(),
(String) instruction.operand(1)
)
);
}
}

/**
* Dup instruction handler.
* @since 0.1
Expand Down
71 changes: 71 additions & 0 deletions src/test/java/org/eolang/opeo/ast/InstanceFieldTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* 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.Directives;
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 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.hasXPaths(
"./o[@name='method']",
"./o[@name='method']/o[@base='.bar']",
"./o[@name='method']/o[@base='.bar']/o[@base='$']"
)
);
}
}
85 changes: 85 additions & 0 deletions src/test/java/org/eolang/opeo/vmachine/DecompilerMachineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
*/
package org.eolang.opeo.vmachine;

import org.cactoos.text.TextOf;
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}.
Expand Down Expand Up @@ -213,4 +216,86 @@ void decompilesNestedInstanceCallWithArguments() {
)
);
}

/**
* Test decompilation of instance field access.
* <p>
* {@code
* this.a + this.b;
* }
* </p>
*/
@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)"
)
);
}

/**
* Test decompilation of instance field access and method invocation.
* <p>
* {@code
* this.a.intValue() + 1;
* }
* </p>
*/
@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.INVOKEVIRTUAL, "App", "intValue", "()I"),
new OpcodeInstruction(Opcodes.ICONST_1),
new OpcodeInstruction(Opcodes.IADD)
),
Matchers.equalTo(
"((this.a).intValue) + (1)"
)
);
}

@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",
""
)
)
);
}
}
12 changes: 2 additions & 10 deletions src/test/resources/packs/simple_objects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,7 @@ eo:
seq > @
tuple
$
opcode > GETFIELD
180
"com/example/A"
"x"
"I"
.x
2
opcode > IMUL
104
Expand Down Expand Up @@ -175,11 +171,7 @@ eo:
seq > @
tuple
$
opcode > GETFIELD
180
"com/example/B"
"a"
"Lcom/example/A;"
.a
.foo
.plus
1
Expand Down

0 comments on commit 0c51a6f

Please sign in to comment.