diff --git a/core/src/main/java/org/teavm/model/text/InstructionStringifier.java b/core/src/main/java/org/teavm/model/text/InstructionStringifier.java index b54afacac..d6487eff4 100644 --- a/core/src/main/java/org/teavm/model/text/InstructionStringifier.java +++ b/core/src/main/java/org/teavm/model/text/InstructionStringifier.java @@ -314,7 +314,7 @@ class InstructionStringifier implements InstructionReader { @Override public void createArray(VariableReader receiver, ValueType itemType, List dimensions) { - sb.append("@").append(receiver.getIndex()).append(" := new "); + sb.append("@").append(receiver.getIndex()).append(" := newArray "); escapeIdentifierIfNeeded(itemType.toString(), sb); sb.append("["); @@ -329,9 +329,8 @@ class InstructionStringifier implements InstructionReader { @Override public void create(VariableReader receiver, String type) { - sb.append("@").append(receiver.getIndex()).append(" := new "); + sb.append("@").append(receiver.getIndex()).append(" := newArray "); escapeIdentifierIfNeeded(type, sb); - sb.append(""); } @Override diff --git a/core/src/main/java/org/teavm/model/text/ListingParser.java b/core/src/main/java/org/teavm/model/text/ListingParser.java index 4ba7bffbd..4b29fb269 100644 --- a/core/src/main/java/org/teavm/model/text/ListingParser.java +++ b/core/src/main/java/org/teavm/model/text/ListingParser.java @@ -34,6 +34,7 @@ import org.teavm.model.TextLocation; import org.teavm.model.ValueType; import org.teavm.model.Variable; import org.teavm.model.instructions.ArrayElementType; +import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingInstruction; @@ -46,19 +47,31 @@ import org.teavm.model.instructions.CastIntegerDirection; import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastNumberInstruction; import org.teavm.model.instructions.ClassConstantInstruction; +import org.teavm.model.instructions.CloneArrayInstruction; +import org.teavm.model.instructions.ConstructArrayInstruction; +import org.teavm.model.instructions.ConstructInstruction; +import org.teavm.model.instructions.ConstructMultiArrayInstruction; import org.teavm.model.instructions.DoubleConstantInstruction; import org.teavm.model.instructions.EmptyInstruction; import org.teavm.model.instructions.ExitInstruction; import org.teavm.model.instructions.FloatConstantInstruction; +import org.teavm.model.instructions.InitClassInstruction; import org.teavm.model.instructions.IntegerConstantInstruction; import org.teavm.model.instructions.IntegerSubtype; import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvokeInstruction; +import org.teavm.model.instructions.IsInstanceInstruction; import org.teavm.model.instructions.JumpInstruction; import org.teavm.model.instructions.LongConstantInstruction; +import org.teavm.model.instructions.MonitorEnterInstruction; +import org.teavm.model.instructions.MonitorExitInstruction; +import org.teavm.model.instructions.NegateInstruction; +import org.teavm.model.instructions.NullCheckInstruction; import org.teavm.model.instructions.NumericOperandType; import org.teavm.model.instructions.PutElementInstruction; +import org.teavm.model.instructions.RaiseInstruction; import org.teavm.model.instructions.StringConstantInstruction; +import org.teavm.model.instructions.UnwrapArrayInstruction; public class ListingParser { private Program program; @@ -200,6 +213,14 @@ public class ListingParser { block.getInstructions().add(insn); break; } + case "throw": { + lexer.nextToken(); + RaiseInstruction insn = new RaiseInstruction(); + insn.setLocation(currentLocation); + insn.setException(expectVariable()); + block.getInstructions().add(insn); + break; + } case "if": { lexer.nextToken(); parseIf(block); @@ -211,6 +232,32 @@ public class ListingParser { parseInvoke(block, null); break; } + case "initClass": { + lexer.nextToken(); + InitClassInstruction insn = new InitClassInstruction(); + expect(ListingToken.IDENTIFIER); + insn.setClassName((String) lexer.getTokenValue()); + lexer.nextToken(); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } + case "monitorEnter": { + lexer.nextToken(); + MonitorEnterInstruction insn = new MonitorEnterInstruction(); + insn.setObjectRef(expectVariable()); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } + case "monitorExit": { + lexer.nextToken(); + MonitorExitInstruction insn = new MonitorExitInstruction(); + insn.setObjectRef(expectVariable()); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } default: unexpected(); break; @@ -299,6 +346,51 @@ public class ListingParser { case "cast": parseCast(block, receiver); break; + case "new": + parseNew(block, receiver); + break; + case "newArray": + parseNewArray(block, receiver); + break; + case "nullCheck": { + lexer.nextToken(); + NullCheckInstruction insn = new NullCheckInstruction(); + insn.setReceiver(receiver); + insn.setValue(expectVariable()); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } + case "data": { + lexer.nextToken(); + Variable value = expectVariable(); + expectKeyword("as"); + ArrayElementType type = expectArrayType(); + UnwrapArrayInstruction insn = new UnwrapArrayInstruction(type); + insn.setArray(value); + insn.setReceiver(receiver); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } + case "lengthOf": { + lexer.nextToken(); + ArrayLengthInstruction insn = new ArrayLengthInstruction(); + insn.setArray(expectVariable()); + insn.setReceiver(receiver); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } + case "clone": { + lexer.nextToken(); + CloneArrayInstruction insn = new CloneArrayInstruction(); + insn.setArray(expectVariable()); + insn.setReceiver(receiver); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } default: unexpected(); break; @@ -325,6 +417,10 @@ public class ListingParser { parseStringConstant(block, receiver); break; } + case SUBTRACT: { + parseNegate(block, receiver); + break; + } default: unexpected(); } @@ -380,6 +476,17 @@ public class ListingParser { case "compareTo": parseBinary(block, receiver, variable, BinaryOperation.COMPARE); break; + case "instanceOf": { + lexer.nextToken(); + ValueType type = expectValueType(); + IsInstanceInstruction insn = new IsInstanceInstruction(); + insn.setValue(variable); + insn.setReceiver(receiver); + insn.setType(type); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + break; + } default: unexpected(); break; @@ -450,13 +557,7 @@ public class ListingParser { } private void parseClassLiteral(BasicBlock block, Variable receiver) throws IOException, ListingParseException { - expect(ListingToken.IDENTIFIER); - String typeString = (String) lexer.getTokenValue(); - ValueType type = ValueType.parseIfPossible(typeString); - if (type == null) { - throw new ListingParseException("Unparseable type: " + typeString, lexer.getTokenStart()); - } - lexer.nextToken(); + ValueType type = expectValueType(); ClassConstantInstruction insn = new ClassConstantInstruction(); insn.setReceiver(receiver); @@ -510,6 +611,18 @@ public class ListingParser { lexer.nextToken(); } + private void parseNegate(BasicBlock block, Variable receiver) throws IOException, ListingParseException { + lexer.nextToken(); + Variable value = expectVariable(); + expectKeyword("as"); + NumericOperandType type = expectNumericType(); + NegateInstruction insn = new NegateInstruction(type); + insn.setReceiver(receiver); + insn.setOperand(value); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + } + private void parseInvoke(BasicBlock block, Variable receiver) throws IOException, ListingParseException { InvokeInstruction insn = new InvokeInstruction(); insn.setReceiver(receiver); @@ -665,12 +778,7 @@ public class ListingParser { private void parseObjectCast(BasicBlock block, Variable receiver, Variable value) throws IOException, ListingParseException { lexer.nextToken(); - expect(ListingToken.IDENTIFIER); - ValueType type = ValueType.parseIfPossible((String) lexer.getTokenValue()); - if (type == null) { - throw new ListingParseException("Unparseable type", lexer.getTokenStart()); - } - lexer.nextToken(); + ValueType type = expectValueType(); CastInstruction insn = new CastInstruction(); insn.setReceiver(receiver); @@ -680,6 +788,48 @@ public class ListingParser { block.getInstructions().add(insn); } + private void parseNew(BasicBlock block, Variable receiver) throws IOException, ListingParseException { + lexer.nextToken(); + expect(ListingToken.IDENTIFIER); + String type = (String) lexer.getTokenValue(); + lexer.nextToken(); + + ConstructInstruction insn = new ConstructInstruction(); + insn.setReceiver(receiver); + insn.setType(type); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + } + + private void parseNewArray(BasicBlock block, Variable receiver) throws IOException, ListingParseException { + lexer.nextToken(); + ValueType type = expectValueType(); + List dimensions = new ArrayList<>(); + expect(ListingToken.LEFT_SQUARE_BRACKET); + do { + lexer.nextToken(); + dimensions.add(expectVariable()); + } while (lexer.getToken() == ListingToken.COMMA); + expect(ListingToken.RIGHT_SQUARE_BRACKET); + lexer.nextToken(); + + if (dimensions.size() == 1) { + ConstructArrayInstruction insn = new ConstructArrayInstruction(); + insn.setReceiver(receiver); + insn.setItemType(type); + insn.setSize(dimensions.get(0)); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + } else { + ConstructMultiArrayInstruction insn = new ConstructMultiArrayInstruction(); + insn.setReceiver(receiver); + insn.setItemType(type); + insn.getDimensions().addAll(dimensions); + insn.setLocation(currentLocation); + block.getInstructions().add(insn); + } + } + private void parseIf(BasicBlock block) throws IOException, ListingParseException { Variable first = expectVariable(); @@ -825,6 +975,16 @@ public class ListingParser { return type; } + private ValueType expectValueType() throws IOException, ListingParseException { + expect(ListingToken.IDENTIFIER); + ValueType type = ValueType.parseIfPossible((String) lexer.getTokenValue()); + if (type == null) { + throw new ListingParseException("Unparseable type", lexer.getTokenStart()); + } + lexer.nextToken(); + return type; + } + private Variable expectVariable() throws IOException, ListingParseException { expect(ListingToken.VARIABLE); String variableName = (String) lexer.getTokenValue(); diff --git a/core/src/test/java/org/teavm/model/text/ParserTest.java b/core/src/test/java/org/teavm/model/text/ParserTest.java index 777858f6c..1b3fd6b8f 100644 --- a/core/src/test/java/org/teavm/model/text/ParserTest.java +++ b/core/src/test/java/org/teavm/model/text/ParserTest.java @@ -30,6 +30,9 @@ import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastNumberInstruction; import org.teavm.model.instructions.ClassConstantInstruction; +import org.teavm.model.instructions.ConstructArrayInstruction; +import org.teavm.model.instructions.ConstructInstruction; +import org.teavm.model.instructions.ConstructMultiArrayInstruction; import org.teavm.model.instructions.DoubleConstantInstruction; import org.teavm.model.instructions.FloatConstantInstruction; import org.teavm.model.instructions.IntegerConstantInstruction; @@ -117,6 +120,22 @@ public class ParserTest { assertTrue(block.getInstructions().get(3) instanceof CastNumberInstruction); } + @Test + public void operations() throws Exception { + runTest("operations"); + } + + @Test + public void create() throws Exception { + Program program = runTest("create"); + assertEquals(1, program.basicBlockCount()); + + BasicBlock block = program.basicBlockAt(0); + assertTrue(block.getInstructions().get(0) instanceof ConstructInstruction); + assertTrue(block.getInstructions().get(1) instanceof ConstructArrayInstruction); + assertTrue(block.getInstructions().get(2) instanceof ConstructMultiArrayInstruction); + } + private Program runTest(String name) throws IOException { ClassLoader classLoader = ParserTest.class.getClassLoader(); String path = "model/text/" + name + ".txt"; diff --git a/core/src/test/resources/model/text/create.txt b/core/src/test/resources/model/text/create.txt new file mode 100644 index 000000000..80566e664 --- /dev/null +++ b/core/src/test/resources/model/text/create.txt @@ -0,0 +1,5 @@ +$block + @a := new java.lang.String + @b := newArray `Ljava/lang/String;` [@size] + @c := newArray I [@h, @w] + return \ No newline at end of file diff --git a/core/src/test/resources/model/text/operations.txt b/core/src/test/resources/model/text/operations.txt new file mode 100644 index 000000000..53603e1d0 --- /dev/null +++ b/core/src/test/resources/model/text/operations.txt @@ -0,0 +1,21 @@ +$block + @r1 := @a + @b as int + @r2 := @c - @d as long + @r3 := @e * @f as float + @r4 := @g % @h as double + @r5 := @a compareTo @b as int + @r6 := @a >> @b as int + @r7 := @a >>> @b as int + @r8 := @a & @b as int + @r8 := @a | @b as int + @r8 := @a ^ @b as int + @r9 := -@a as int + @r10 := @i instanceOf `[J` + initClass java.lang.Math + monitorEnter @i + @r11 := nullCheck @i + @r12 := data @i as long + @r13 := lengthOf @i + @r14 := clone @i + monitorExit @i + throw @exception \ No newline at end of file