From b1522b809bc002cd92fd5516da0fb8c2e941cdd4 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Wed, 26 Mar 2025 10:34:26 +0000 Subject: [PATCH] Part 1 Part 2 Part 3 Part 4 Temp disable stackvm AST revision to capture load/store array/field info --- .../ezlang/compiler/CompiledFunction.java | 75 +++++---- .../ezlang/compiler/Instruction.java | 17 +- .../SparseConditionalConstantPropagation.java | 2 - .../ezlang/interpreter/Interpreter.java | 18 +-- .../ezlang/compiler/TestCompiler.java | 8 +- .../ezlang/compiler/TestSSATransform.java | 24 +-- .../ezlang/parser/AST.java | 150 +++++++++++++----- .../ezlang/parser/ASTVisitor.java | 8 +- .../ezlang/parser/Parser.java | 39 +++-- .../ezlang/parser/TestParser.java | 3 + .../ezlang/compiler/CompiledFunction.java | 73 +++++---- .../ezlang/compiler/Instruction.java | 17 +- .../ezlang/interpreter/Interpreter.java | 18 +-- .../ezlang/compiler/TestCompiler.java | 8 +- .../ezlang/semantic/SemaAssignTypes.java | 89 +++++++++-- .../ezlang/semantic/SemaDefineTypes.java | 18 ++- .../ezlang/compiler/CompiledFunction.java | 73 +++++---- .../ezlang/compiler/Instruction.java | 32 ++-- .../ezlang/compiler/TestCompiler.java | 15 +- 19 files changed, 420 insertions(+), 267 deletions(-) diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index 4eb3bf3..5d237e0 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -309,11 +309,17 @@ private boolean compileExpr(AST.Expr expr) { case AST.NewExpr newExpr -> { return compileNewExpr(newExpr); } - case AST.ArrayIndexExpr arrayIndexExpr -> { - return compileArrayIndexExpr(arrayIndexExpr); + case AST.InitExpr initExpr -> { + return compileInitExpr(initExpr); } - case AST.FieldExpr fieldExpr -> { - return compileFieldExpr(fieldExpr); + case AST.ArrayLoadExpr arrayLoadExpr -> { + return compileArrayIndexExpr(arrayLoadExpr); + } + case AST.ArrayStoreExpr arrayStoreExpr -> { + return compileArrayStoreExpr(arrayStoreExpr); + } + case AST.GetFieldExpr getFieldExpr -> { + return compileFieldExpr(getFieldExpr); } case AST.SetFieldExpr setFieldExpr -> { return compileSetFieldExpr(setFieldExpr); @@ -370,7 +376,7 @@ else if (t instanceof Type.TypeNullable ptr && throw new CompilerException("Unexpected type: " + t); } - private boolean compileFieldExpr(AST.FieldExpr fieldExpr) { + private boolean compileFieldExpr(AST.GetFieldExpr fieldExpr) { Type.TypeStruct typeStruct = getStructType(fieldExpr.object.type); int fieldIndex = typeStruct.getFieldIndex(fieldExpr.fieldName); if (fieldIndex < 0) @@ -382,7 +388,7 @@ private boolean compileFieldExpr(AST.FieldExpr fieldExpr) { return true; } - private boolean compileArrayIndexExpr(AST.ArrayIndexExpr arrayIndexExpr) { + private boolean compileArrayIndexExpr(AST.ArrayLoadExpr arrayIndexExpr) { compileExpr(arrayIndexExpr.array); boolean indexed = compileExpr(arrayIndexExpr.expr); if (indexed) @@ -394,11 +400,15 @@ private boolean compileArrayIndexExpr(AST.ArrayIndexExpr arrayIndexExpr) { } private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { - Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.objectType; + Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.object.type; int fieldIndex = structType.getFieldIndex(setFieldExpr.fieldName); if (fieldIndex == -1) throw new CompilerException("Field " + setFieldExpr.fieldName + " not found in struct " + structType.name); - pushOperand(new Operand.LoadFieldOperand(top(), setFieldExpr.fieldName, fieldIndex)); + if (setFieldExpr instanceof AST.InitFieldExpr) + pushOperand(top()); + else + compileExpr(setFieldExpr.object); + pushOperand(new Operand.LoadFieldOperand(pop(), setFieldExpr.fieldName, fieldIndex)); boolean indexed = compileExpr(setFieldExpr.value); if (indexed) codeIndexedLoad(); @@ -406,22 +416,34 @@ private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { return false; } + private boolean compileArrayStoreExpr(AST.ArrayStoreExpr arrayStoreExpr) { + if (arrayStoreExpr instanceof AST.ArrayInitExpr) + pushOperand(top()); // Array was created by new + else + compileExpr(arrayStoreExpr.array); + boolean indexed = compileExpr(arrayStoreExpr.expr); + if (indexed) + codeIndexedLoad(); + Operand index = pop(); + Operand array = pop(); + pushOperand(new Operand.LoadIndexedOperand(array, index)); + indexed = compileExpr(arrayStoreExpr.value); + if (indexed) + codeIndexedLoad(); + codeIndexedStore(); + return false; + } + private boolean compileNewExpr(AST.NewExpr newExpr) { codeNew(newExpr.type); - if (newExpr.initExprList != null && !newExpr.initExprList.isEmpty()) { - if (newExpr.type instanceof Type.TypeArray) { - for (AST.Expr expr : newExpr.initExprList) { - // Maybe have specific AST similar to how we have SetFieldExpr? - boolean indexed = compileExpr(expr); - if (indexed) - codeIndexedLoad(); - codeStoreAppend(); - } - } - else if (newExpr.type instanceof Type.TypeStruct) { - for (AST.Expr expr : newExpr.initExprList) { - compileExpr(expr); - } + return false; + } + + private boolean compileInitExpr(AST.InitExpr initExpr) { + compileExpr(initExpr.newExpr); + if (initExpr.initExprList != null && !initExpr.initExprList.isEmpty()) { + for (AST.Expr expr : initExpr.initExprList) { + compileExpr(expr); } } return false; @@ -640,15 +662,6 @@ else if (type instanceof Type.TypeStruct typeStruct) throw new CompilerException("Unexpected type: " + type); } - private void codeStoreAppend() { - var operand = issa.read(pop()); - Operand.RegisterOperand arrayOperand = (Operand.RegisterOperand) issa.read(top()); - var insn = new Instruction.AStoreAppend(arrayOperand, operand); - issa.recordUse(arrayOperand, insn); - issa.recordUse(operand, insn); - code(insn); - } - private void codeNewArray(Type.TypeArray typeArray) { var temp = createTemp(typeArray); var target = (Operand.RegisterOperand) issa.write(temp); diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index 7bb016b..0ab1203 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -22,9 +22,8 @@ public abstract class Instruction { static final int I_NEW_STRUCT = 11; static final int I_ARRAY_STORE = 12; static final int I_ARRAY_LOAD = 13; - static final int I_ARRAY_APPEND = 14; - static final int I_FIELD_GET = 15; - static final int I_FIELD_SET = 16; + static final int I_FIELD_GET = 14; + static final int I_FIELD_SET = 15; public final int opcode; protected Operand.RegisterOperand def; @@ -271,18 +270,6 @@ public StringBuilder toStr(StringBuilder sb) { } } - public static class AStoreAppend extends Instruction { - public AStoreAppend(Operand.RegisterOperand array, Operand value) { - super(I_ARRAY_APPEND, (Operand.RegisterOperand) null, array, value); - } - public Operand.RegisterOperand array() { return (Operand.RegisterOperand) uses[0]; } - public Operand value() { return uses[1]; } - @Override - public StringBuilder toStr(StringBuilder sb) { - return sb.append(uses[0]).append(".append(").append(uses[1]).append(")"); - } - } - public static class ConditionalBranch extends Instruction { public final BasicBlock trueBlock; public final BasicBlock falseBlock; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java index c83ee31..38f0bc6 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java @@ -421,8 +421,6 @@ else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand) var cell = valueLattice.get(newStructInst.destOperand().reg); changed = cell.setKind(V_VARYING); } - case Instruction.AStoreAppend arrayAppendInst -> { - } case Instruction.ArrayStore arrayStoreInst -> { } case Instruction.ArrayLoad arrayLoadInst -> { diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java index d59e1f0..66de388 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -205,19 +205,6 @@ else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand) case Instruction.NewStruct newStructInst -> { execStack.stack[base + newStructInst.destOperand().frameSlot()] = new Value.StructValue(newStructInst.type); } - case Instruction.AStoreAppend arrayAppendInst -> { - Value.ArrayValue arrayValue = (Value.ArrayValue) execStack.stack[base + arrayAppendInst.array().frameSlot()]; - if (arrayAppendInst.value() instanceof Operand.ConstantOperand constant) { - arrayValue.values.add(new Value.IntegerValue(constant.value)); - } - else if (arrayAppendInst.value() instanceof Operand.NullConstantOperand) { - arrayValue.values.add(new Value.NullValue()); - } - else if (arrayAppendInst.value() instanceof Operand.RegisterOperand registerOperand) { - arrayValue.values.add(execStack.stack[base + registerOperand.frameSlot()]); - } - else throw new IllegalStateException(); - } case Instruction.ArrayStore arrayStoreInst -> { if (arrayStoreInst.arrayOperand() instanceof Operand.RegisterOperand arrayOperand) { Value.ArrayValue arrayValue = (Value.ArrayValue) execStack.stack[base + arrayOperand.frameSlot()]; @@ -241,7 +228,10 @@ else if (arrayStoreInst.sourceOperand() instanceof Operand.RegisterOperand regis value = execStack.stack[base + registerOperand.frameSlot()]; } else throw new IllegalStateException(); - arrayValue.values.set(index, value); + if (index == arrayValue.values.size()) + arrayValue.values.add(value); + else + arrayValue.values.set(index, value); } else throw new IllegalStateException(); } case Instruction.ArrayLoad arrayLoadInst -> { diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java index fa148b6..b6873ec 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java @@ -215,9 +215,9 @@ func foo()->[Int] { Assert.assertEquals(""" L0: %t0 = New([Int]) - %t0.append(1) - %t0.append(2) - %t0.append(3) + %t0[0] = 1 + %t0[1] = 2 + %t0[2] = 3 ret %t0 goto L1 L1: @@ -236,7 +236,7 @@ func foo(n: Int) -> [Int] { L0: arg n %t1 = New([Int]) - %t1.append(n) + %t1[0] = n ret %t1 goto L1 L1: diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java index 39aec29..a605c93 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java @@ -1602,8 +1602,8 @@ func foo()->Int { ========== L0: %t2 = New([Int]) - %t2.append(1) - %t2.append(2) + %t2[0] = 1 + %t2[1] = 2 arr = %t2 arr[0] = 10 %t3 = arr[0] @@ -1615,8 +1615,8 @@ func foo()->Int { ========= L0: %t2_0 = New([Int]) - %t2_0.append(1) - %t2_0.append(2) + %t2_0[0] = 1 + %t2_0[1] = 2 arr_0 = %t2_0 arr_0[0] = 10 %t3_0 = arr_0[0] @@ -1628,8 +1628,8 @@ func foo()->Int { ================= L0: %t2_0 = New([Int]) - %t2_0.append(1) - %t2_0.append(2) + %t2_0[0] = 1 + %t2_0[1] = 2 arr_0 = %t2_0 arr_0[0] = 10 %t3_0 = arr_0[0] @@ -2738,8 +2738,8 @@ func foo()->Int %t1 = New([Foo?]) %t2 = New(Foo) %t2.i = 1 - %t1.append(%t2) - %t1.append(null) + %t1[0] = %t2 + %t1[1] = null f = %t1 %t3 = f[1] %t4 = null==%t3 @@ -2762,8 +2762,8 @@ func foo()->Int %t1_0 = New([Foo?]) %t2_0 = New(Foo) %t2_0.i = 1 - %t1_0.append(%t2_0) - %t1_0.append(null) + %t1_0[0] = %t2_0 + %t1_0[1] = null f_0 = %t1_0 %t3_0 = f_0[1] %t4_0 = null==%t3_0 @@ -2787,8 +2787,8 @@ func foo()->Int %t1_0 = New([Foo?]) %t2_0 = New(Foo) %t2_0.i = 1 - %t1_0.append(%t2_0) - %t1_0.append(null) + %t1_0[0] = %t2_0 + %t1_0[1] = null f_0 = %t1_0 %t3_0 = f_0[1] %t4_0 = null==%t3_0 diff --git a/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java b/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java index 969625d..1fbb4f7 100644 --- a/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java +++ b/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java @@ -137,7 +137,12 @@ public StringBuilder toStr(StringBuilder sb) { } args[i].toStr(sb); } - sb.append(")\n"); + sb.append(")"); + if (returnType != null) { + sb.append("->"); + returnType.toStr(sb); + } + sb.append("\n"); return block.toStr(sb); } @@ -368,18 +373,13 @@ public void accept(ASTVisitor visitor) { } } - // Array Index - public static class ArrayIndexExpr extends Expr { + // array[index] + public static class ArrayLoadExpr extends Expr { public final Expr array; public final Expr expr; - public final boolean loading; - public ArrayIndexExpr(Expr array, Expr expr) { - this(array, expr, true); - } - public ArrayIndexExpr(Expr array, Expr expr, boolean loading) { + public ArrayLoadExpr(Expr array, Expr expr) { this.array = array; this.expr = expr; - this.loading = loading; } @Override public StringBuilder toStr(StringBuilder sb) { @@ -400,17 +400,55 @@ public void accept(ASTVisitor visitor) { } } - public static class FieldExpr extends Expr { + // array[index] = value + public static class ArrayStoreExpr extends Expr { + public final Expr array; + public final Expr expr; + public final Expr value; + public ArrayStoreExpr(Expr array, Expr expr, Expr value) { + this.array = array; + this.expr = expr; + this.value = value; + } + @Override + public StringBuilder toStr(StringBuilder sb) { + array.toStr(sb); + sb.append("["); + expr.toStr(sb); + return sb.append("]").append("=").append(value); + } + @Override + public void accept(ASTVisitor visitor) { + visitor = visitor.visit(this, true); + if (visitor == null) + return; + array.accept(visitor); + expr.accept(visitor); + value.accept(visitor); + visitor.visit(this, false); + } + } + + /** + * Used inside InitExpr + * Specializes how we display + */ + public static class ArrayInitExpr extends ArrayStoreExpr { + public ArrayInitExpr(Expr array, Expr expr, Expr value) { + super(array, expr, value); + } + @Override + public StringBuilder toStr(StringBuilder sb) { + return sb.append(value); + } + } + + public static class GetFieldExpr extends Expr { public final Expr object; public final String fieldName; - public final boolean loading; - public FieldExpr(Expr object, String fieldName) { - this(object, fieldName, true); - } - public FieldExpr(Expr object, String fieldName, boolean loading) { + public GetFieldExpr(Expr object, String fieldName) { this.object = object; this.fieldName = fieldName; - this.loading = loading; } @Override public StringBuilder toStr(StringBuilder sb) { @@ -428,6 +466,45 @@ public void accept(ASTVisitor visitor) { } } + public static class SetFieldExpr extends Expr { + public final Expr object; + public final String fieldName; + public final Expr value; + public SetFieldExpr(Expr object, String fieldName, Expr value) { + this.object = object; + this.fieldName = fieldName; + this.value = value; + } + @Override + public StringBuilder toStr(StringBuilder sb) { + object.toStr(sb); + return sb.append(".").append(fieldName).append("=").append(value); + } + @Override + public void accept(ASTVisitor visitor) { + visitor = visitor.visit(this, true); + if (visitor == null) + return; + object.accept(visitor); + value.accept(visitor); + visitor.visit(this, false); + } + } + + /** + * Used inside InitExpr + * Specializes how we display + */ + public static class InitFieldExpr extends SetFieldExpr { + public InitFieldExpr(Expr object, String fieldName, Expr value) { + super(object, fieldName, value); + } + @Override + public StringBuilder toStr(StringBuilder sb) { + return sb.append(fieldName).append("=").append(value); + } + } + public static class CallExpr extends Expr { public final Expr callee; public final List args; @@ -462,44 +539,45 @@ public void accept(ASTVisitor visitor) { } } - public static class SetFieldExpr extends Expr { - public final String fieldName; - public final AST.Expr value; - public Type objectType; - public SetFieldExpr(String fieldName, Expr value) { - this.fieldName = fieldName; - this.value = value; + /** + * new T + * result type is T + */ + public static class NewExpr extends Expr { + public final TypeExpr typeExpr; + public NewExpr(TypeExpr typeExpr) { + this.typeExpr = typeExpr; } @Override public StringBuilder toStr(StringBuilder sb) { - if (fieldName != null) { - sb.append(fieldName).append("="); - } - value.toStr(sb); + sb.append("new "); + typeExpr.toStr(sb); return sb; } - @Override public void accept(ASTVisitor visitor) { visitor = visitor.visit(this, true); if (visitor == null) return; - value.accept(visitor); + typeExpr.accept(visitor); visitor.visit(this, false); } } - public static class NewExpr extends Expr { - public final TypeExpr typeExpr; + /** + * new T { initializers } + * result type is T + */ + public static class InitExpr extends Expr { + public final NewExpr newExpr; public final List initExprList; - public NewExpr(TypeExpr typeExpr, List initExprList) { - this.typeExpr = typeExpr; + public InitExpr(NewExpr newExpr, List initExprList) { + this.newExpr = newExpr; this.initExprList = initExprList; } @Override public StringBuilder toStr(StringBuilder sb) { - sb.append("new "); - typeExpr.toStr(sb); + newExpr.toStr(sb); sb.append("{"); boolean first = true; for (Expr expr: initExprList) { @@ -517,7 +595,7 @@ public void accept(ASTVisitor visitor) { visitor = visitor.visit(this, true); if (visitor == null) return; - typeExpr.accept(visitor); + newExpr.accept(visitor); for (Expr expr: initExprList) { expr.accept(visitor); } diff --git a/parser/src/main/java/com/compilerprogramming/ezlang/parser/ASTVisitor.java b/parser/src/main/java/com/compilerprogramming/ezlang/parser/ASTVisitor.java index adf901a..d12f0dc 100644 --- a/parser/src/main/java/com/compilerprogramming/ezlang/parser/ASTVisitor.java +++ b/parser/src/main/java/com/compilerprogramming/ezlang/parser/ASTVisitor.java @@ -7,17 +7,19 @@ public interface ASTVisitor { ASTVisitor visit(AST.VarDecl varDecl, boolean enter); ASTVisitor visit(AST.BinaryExpr binaryExpr, boolean enter); ASTVisitor visit(AST.UnaryExpr unaryExpr, boolean enter); - ASTVisitor visit(AST.FieldExpr fieldExpr, boolean enter); + ASTVisitor visit(AST.GetFieldExpr fieldExpr, boolean enter); + ASTVisitor visit(AST.SetFieldExpr fieldExpr, boolean enter); ASTVisitor visit(AST.CallExpr callExpr, boolean enter); - ASTVisitor visit(AST.SetFieldExpr setFieldExpr, boolean enter); ASTVisitor visit(AST.SimpleTypeExpr simpleTypeExpr, boolean enter); ASTVisitor visit(AST.NullableSimpleTypeExpr simpleTypeExpr, boolean enter); ASTVisitor visit(AST.ArrayTypeExpr arrayTypeExpr, boolean enter); ASTVisitor visit(AST.NullableArrayTypeExpr arrayTypeExpr, boolean enter); ASTVisitor visit(AST.ReturnTypeExpr returnTypeExpr, boolean enter); ASTVisitor visit(AST.LiteralExpr literalExpr, boolean enter); - ASTVisitor visit(AST.ArrayIndexExpr arrayIndexExpr, boolean enter); + ASTVisitor visit(AST.ArrayLoadExpr arrayLoadExpr, boolean enter); + ASTVisitor visit(AST.ArrayStoreExpr arrayStoreExpr, boolean enter); ASTVisitor visit(AST.NewExpr newExpr, boolean enter); + ASTVisitor visit(AST.InitExpr initExpr, boolean enter); ASTVisitor visit(AST.NameExpr nameExpr, boolean enter); ASTVisitor visit(AST.BreakStmt breakStmt, boolean enter); ASTVisitor visit(AST.ContinueStmt continueStmt, boolean enter); diff --git a/parser/src/main/java/com/compilerprogramming/ezlang/parser/Parser.java b/parser/src/main/java/com/compilerprogramming/ezlang/parser/Parser.java index 97f36fc..f7b4951 100644 --- a/parser/src/main/java/com/compilerprogramming/ezlang/parser/Parser.java +++ b/parser/src/main/java/com/compilerprogramming/ezlang/parser/Parser.java @@ -246,19 +246,15 @@ private AST.Stmt parseAssign(Lexer lexer) { testPunctuation(lexer, ";"); if (rhs == null) return new AST.ExprStmt(lhs); - return new AST.AssignStmt(storing(lhs), rhs); - } - - private AST.Expr storing(AST.Expr lhs) { - if (lhs instanceof AST.ArrayIndexExpr arrayIndexExpr && - arrayIndexExpr.loading) { - return new AST.ArrayIndexExpr(arrayIndexExpr.array, arrayIndexExpr.expr, false); - } - else if (lhs instanceof AST.FieldExpr fieldExpr && - fieldExpr.loading) { - return new AST.FieldExpr(fieldExpr.object, fieldExpr.fieldName, false); + else { + if (lhs instanceof AST.ArrayLoadExpr arrayLoadExpr) { + return new AST.ExprStmt(new AST.ArrayStoreExpr(arrayLoadExpr.array, arrayLoadExpr.expr, rhs)); + } + else if (lhs instanceof AST.GetFieldExpr getFieldExpr) { + return new AST.ExprStmt(new AST.SetFieldExpr(getFieldExpr.object, getFieldExpr.fieldName, rhs)); + } } - return lhs; + return new AST.AssignStmt(lhs, rhs); } private AST.Expr parseBool(Lexer lexer) { @@ -333,18 +329,27 @@ private AST.Expr parseUnary(Lexer lexer) { private AST.Expr parseNew(Lexer lexer) { matchIdentifier(lexer, "new"); AST.TypeExpr resultType = parseTypeExpr(lexer); + var newExpr = new AST.NewExpr(resultType); List initExpr = new ArrayList<>(); + int initType = 0; + int index = 0; if (testPunctuation(lexer, "{")) { while (!isToken(currentToken, "}")) { if (currentToken.kind == Token.Kind.IDENT && lexer.peekChar() == '=') { + if (initType == 0) initType = 1; + else if (initType != 1) throw new CompilerException("Cannot mix initializer expressions"); String fieldname = currentToken.str; nextToken(lexer); matchPunctuation(lexer, "="); AST.Expr value = parseBool(lexer); - initExpr.add(new AST.SetFieldExpr(fieldname, value)); + initExpr.add(new AST.InitFieldExpr(newExpr, fieldname, value)); } else { - initExpr.add(parseBool(lexer)); + if (initType == 0) initType = 2; + else if (initType != 2) throw new CompilerException("Cannot mix initializer expressions"); + var indexLit = Integer.valueOf(index++); + var indexExpr = new AST.LiteralExpr(Token.newNum(indexLit,indexLit.toString(),0)); + initExpr.add(new AST.ArrayInitExpr(newExpr, indexExpr, parseBool(lexer))); } if (isToken(currentToken, ",")) nextToken(lexer); @@ -352,7 +357,7 @@ private AST.Expr parseNew(Lexer lexer) { } } matchPunctuation(lexer, "}"); - return new AST.NewExpr(resultType, initExpr); + return new AST.InitExpr(newExpr, initExpr); } private AST.Expr parsePrimary(Lexer lexer) { @@ -401,12 +406,12 @@ private AST.Expr parsePostfix(Lexer lexer, AST.Expr primaryExpr) { switch (tok.str) { case "[" -> { AST.Expr expr = parseBool(lexer); - prevExpr = new AST.ArrayIndexExpr(prevExpr, expr); + prevExpr = new AST.ArrayLoadExpr(prevExpr, expr); matchPunctuation(lexer, "]"); } case "." -> { if (currentToken.kind == Token.Kind.IDENT) { - prevExpr = new AST.FieldExpr(prevExpr, currentToken.str); + prevExpr = new AST.GetFieldExpr(prevExpr, currentToken.str); nextToken(lexer); } else diff --git a/parser/src/test/java/com/compilerprogramming/ezlang/parser/TestParser.java b/parser/src/test/java/com/compilerprogramming/ezlang/parser/TestParser.java index c98f54c..101c75d 100644 --- a/parser/src/test/java/com/compilerprogramming/ezlang/parser/TestParser.java +++ b/parser/src/test/java/com/compilerprogramming/ezlang/parser/TestParser.java @@ -36,6 +36,9 @@ func bar() -> Test { func main() { var m = 42 var t: Tree + var array = new [Int] {1,2,3} + array[1] = 42 + t.left = null if (m < 1) print(1) else if (m == 5) diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index b0849e6..0e25924 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -265,11 +265,17 @@ private boolean compileExpr(AST.Expr expr) { case AST.NewExpr newExpr -> { return compileNewExpr(newExpr); } - case AST.ArrayIndexExpr arrayIndexExpr -> { - return compileArrayIndexExpr(arrayIndexExpr); + case AST.InitExpr initExpr -> { + return compileInitExpr(initExpr); } - case AST.FieldExpr fieldExpr -> { - return compileFieldExpr(fieldExpr); + case AST.ArrayLoadExpr arrayLoadExpr -> { + return compileArrayIndexExpr(arrayLoadExpr); + } + case AST.ArrayStoreExpr arrayStoreExpr -> { + return compileArrayStoreExpr(arrayStoreExpr); + } + case AST.GetFieldExpr getFieldExpr -> { + return compileFieldExpr(getFieldExpr); } case AST.SetFieldExpr setFieldExpr -> { return compileSetFieldExpr(setFieldExpr); @@ -327,7 +333,7 @@ else if (t instanceof Type.TypeNullable ptr && throw new CompilerException("Unexpected type: " + t); } - private boolean compileFieldExpr(AST.FieldExpr fieldExpr) { + private boolean compileFieldExpr(AST.GetFieldExpr fieldExpr) { Type.TypeStruct typeStruct = getStructType(fieldExpr.object.type); int fieldIndex = typeStruct.getFieldIndex(fieldExpr.fieldName); if (fieldIndex < 0) @@ -339,7 +345,7 @@ private boolean compileFieldExpr(AST.FieldExpr fieldExpr) { return true; } - private boolean compileArrayIndexExpr(AST.ArrayIndexExpr arrayIndexExpr) { + private boolean compileArrayIndexExpr(AST.ArrayLoadExpr arrayIndexExpr) { compileExpr(arrayIndexExpr.array); boolean indexed = compileExpr(arrayIndexExpr.expr); if (indexed) @@ -351,11 +357,15 @@ private boolean compileArrayIndexExpr(AST.ArrayIndexExpr arrayIndexExpr) { } private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { - Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.objectType; + Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.object.type; int fieldIndex = structType.getFieldIndex(setFieldExpr.fieldName); if (fieldIndex == -1) throw new CompilerException("Field " + setFieldExpr.fieldName + " not found in struct " + structType.name); - pushOperand(new Operand.LoadFieldOperand(top(), setFieldExpr.fieldName, fieldIndex)); + if (setFieldExpr instanceof AST.InitFieldExpr) + pushOperand(top()); + else + compileExpr(setFieldExpr.object); + pushOperand(new Operand.LoadFieldOperand(pop(), setFieldExpr.fieldName, fieldIndex)); boolean indexed = compileExpr(setFieldExpr.value); if (indexed) codeIndexedLoad(); @@ -363,22 +373,34 @@ private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { return false; } + private boolean compileArrayStoreExpr(AST.ArrayStoreExpr arrayStoreExpr) { + if (arrayStoreExpr instanceof AST.ArrayInitExpr) + pushOperand(top()); // Array was created by new + else + compileExpr(arrayStoreExpr.array); + boolean indexed = compileExpr(arrayStoreExpr.expr); + if (indexed) + codeIndexedLoad(); + Operand index = pop(); + Operand array = pop(); + pushOperand(new Operand.LoadIndexedOperand(array, index)); + indexed = compileExpr(arrayStoreExpr.value); + if (indexed) + codeIndexedLoad(); + codeIndexedStore(); + return false; + } + private boolean compileNewExpr(AST.NewExpr newExpr) { codeNew(newExpr.type); - if (newExpr.initExprList != null && !newExpr.initExprList.isEmpty()) { - if (newExpr.type instanceof Type.TypeArray) { - for (AST.Expr expr : newExpr.initExprList) { - // Maybe have specific AST similar to how we have SetFieldExpr? - boolean indexed = compileExpr(expr); - if (indexed) - codeIndexedLoad(); - codeStoreAppend(); - } - } - else if (newExpr.type instanceof Type.TypeStruct) { - for (AST.Expr expr : newExpr.initExprList) { - compileExpr(expr); - } + return false; + } + + private boolean compileInitExpr(AST.InitExpr initExpr) { + compileExpr(initExpr.newExpr); + if (initExpr.initExprList != null && !initExpr.initExprList.isEmpty()) { + for (AST.Expr expr : initExpr.initExprList) { + compileExpr(expr); } } return false; @@ -599,11 +621,4 @@ else if (type instanceof Type.TypeStruct typeStruct) else throw new CompilerException("Unexpected type: " + type); } - - private void codeStoreAppend() { - var operand = pop(); - code(new Instruction.AStoreAppend((Operand.RegisterOperand) top(), operand)); - } - - } diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index 35c1fda..a80169a 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -18,9 +18,8 @@ public abstract class Instruction { static final int I_NEW_STRUCT = 11; static final int I_ARRAY_STORE = 12; static final int I_ARRAY_LOAD = 13; - static final int I_ARRAY_APPEND = 14; - static final int I_FIELD_GET = 15; - static final int I_FIELD_SET = 16; + static final int I_FIELD_GET = 14; + static final int I_FIELD_SET = 15; public final int opcode; protected Operand.RegisterOperand def; @@ -209,18 +208,6 @@ public StringBuilder toStr(StringBuilder sb) { } } - public static class AStoreAppend extends Instruction { - public AStoreAppend(Operand.RegisterOperand array, Operand value) { - super(I_ARRAY_APPEND, (Operand.RegisterOperand) null, array, value); - } - public Operand.RegisterOperand array() { return (Operand.RegisterOperand) uses[0]; } - public Operand value() { return uses[1]; } - @Override - public StringBuilder toStr(StringBuilder sb) { - return sb.append(uses[0]).append(".append(").append(uses[1]).append(")"); - } - } - public static class ConditionalBranch extends Instruction { public final BasicBlock trueBlock; public final BasicBlock falseBlock; diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java index 5ceaeaa..7771700 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -205,19 +205,6 @@ else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand) case Instruction.NewStruct newStructInst -> { execStack.stack[base + newStructInst.destOperand().frameSlot()] = new Value.StructValue(newStructInst.type); } - case Instruction.AStoreAppend arrayAppendInst -> { - Value.ArrayValue arrayValue = (Value.ArrayValue) execStack.stack[base + arrayAppendInst.array().frameSlot()]; - if (arrayAppendInst.value() instanceof Operand.ConstantOperand constant) { - arrayValue.values.add(new Value.IntegerValue(constant.value)); - } - else if (arrayAppendInst.value() instanceof Operand.NullConstantOperand) { - arrayValue.values.add(new Value.NullValue()); - } - else if (arrayAppendInst.value() instanceof Operand.RegisterOperand registerOperand) { - arrayValue.values.add(execStack.stack[base + registerOperand.frameSlot()]); - } - else throw new IllegalStateException(); - } case Instruction.ArrayStore arrayStoreInst -> { if (arrayStoreInst.arrayOperand() instanceof Operand.RegisterOperand arrayOperand) { Value.ArrayValue arrayValue = (Value.ArrayValue) execStack.stack[base + arrayOperand.frameSlot()]; @@ -241,7 +228,10 @@ else if (arrayStoreInst.sourceOperand() instanceof Operand.RegisterOperand regis value = execStack.stack[base + registerOperand.frameSlot()]; } else throw new IllegalStateException(); - arrayValue.values.set(index, value); + if (index == arrayValue.values.size()) + arrayValue.values.add(value); + else + arrayValue.values.set(index, value); } else throw new IllegalStateException(); } case Instruction.ArrayLoad arrayLoadInst -> { diff --git a/registervm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java b/registervm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java index 2deb384..142b8b6 100644 --- a/registervm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java +++ b/registervm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java @@ -204,9 +204,9 @@ func foo()->[Int] { Assert.assertEquals(""" L0: %t0 = New([Int]) - %t0.append(1) - %t0.append(2) - %t0.append(3) + %t0[0] = 1 + %t0[1] = 2 + %t0[2] = 3 ret %t0 goto L1 L1: @@ -224,7 +224,7 @@ func foo(n: Int) -> [Int] { Assert.assertEquals(""" L0: %t1 = New([Int]) - %t1.append(n) + %t1[0] = n ret %t1 goto L1 L1: diff --git a/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaAssignTypes.java b/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaAssignTypes.java index f22c855..25abf39 100644 --- a/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaAssignTypes.java +++ b/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaAssignTypes.java @@ -106,7 +106,7 @@ public ASTVisitor visit(AST.UnaryExpr unaryExpr, boolean enter) { } @Override - public ASTVisitor visit(AST.FieldExpr fieldExpr, boolean enter) { + public ASTVisitor visit(AST.GetFieldExpr fieldExpr, boolean enter) { if (enter) return this; validType(fieldExpr.object.type, false); @@ -127,6 +127,31 @@ else if (fieldExpr.object.type instanceof Type.TypeNullable ptr && return this; } + @Override + public ASTVisitor visit(AST.SetFieldExpr fieldExpr, boolean enter) { + if (enter) + return this; + validType(fieldExpr.object.type, true); + Type.TypeStruct structType = null; + if (fieldExpr.object.type instanceof Type.TypeStruct ts) { + structType = ts; + } + else if (fieldExpr.object.type instanceof Type.TypeNullable ptr && + ptr.baseType instanceof Type.TypeStruct ts) { + structType = ts; + } + else + throw new CompilerException("Unexpected struct type " + fieldExpr.object.type); + var fieldType = structType.getField(fieldExpr.fieldName); + if (fieldType == null) + throw new CompilerException("Struct " + structType + " does not have field named " + fieldExpr.fieldName); + validType(fieldExpr.value.type, true); + checkAssignmentCompatible(fieldType, fieldExpr.value.type); + fieldExpr.type = fieldType; + return this; + } + + @Override public ASTVisitor visit(AST.CallExpr callExpr, boolean enter) { if (!enter) { @@ -140,14 +165,6 @@ public ASTVisitor visit(AST.CallExpr callExpr, boolean enter) { return this; } - @Override - public ASTVisitor visit(AST.SetFieldExpr setFieldExpr, boolean enter) { - if (!enter) { - validType(setFieldExpr.value.type, true); - } - return this; - } - @Override public ASTVisitor visit(AST.SimpleTypeExpr simpleTypeExpr, boolean enter) { return this; @@ -190,7 +207,29 @@ else if (literalExpr.value.kind == Token.Kind.IDENT } @Override - public ASTVisitor visit(AST.ArrayIndexExpr arrayIndexExpr, boolean enter) { + public ASTVisitor visit(AST.ArrayLoadExpr arrayIndexExpr, boolean enter) { + if (!enter) { + validType(arrayIndexExpr.array.type, false); + Type.TypeArray arrayType = null; + if (arrayIndexExpr.array.type instanceof Type.TypeArray ta) { + arrayType = ta; + } + else if (arrayIndexExpr.array.type instanceof Type.TypeNullable ptr && + ptr.baseType instanceof Type.TypeArray ta) { + arrayType = ta; + } + else + throw new CompilerException("Unexpected array type " + arrayIndexExpr.array.type); + if (!(arrayIndexExpr.expr.type instanceof Type.TypeInteger)) + throw new CompilerException("Array index must be integer type"); + arrayIndexExpr.type = arrayType.getElementType(); + validType(arrayIndexExpr.type, false); + } + return this; + } + + @Override + public ASTVisitor visit(AST.ArrayStoreExpr arrayIndexExpr, boolean enter) { if (!enter) { validType(arrayIndexExpr.array.type, false); Type.TypeArray arrayType = null; @@ -207,6 +246,8 @@ else if (arrayIndexExpr.array.type instanceof Type.TypeNullable ptr && throw new CompilerException("Array index must be integer type"); arrayIndexExpr.type = arrayType.getElementType(); validType(arrayIndexExpr.type, false); + validType(arrayIndexExpr.value.type, true); + checkAssignmentCompatible(arrayIndexExpr.type, arrayIndexExpr.value.type); } return this; } @@ -222,22 +263,40 @@ public ASTVisitor visit(AST.NewExpr newExpr, boolean enter) { throw new CompilerException("new cannot be used to create a Nullable type"); if (newExpr.typeExpr.type instanceof Type.TypeStruct typeStruct) { newExpr.type = newExpr.typeExpr.type; - for (AST.Expr expr: newExpr.initExprList) { + } + else if (newExpr.typeExpr.type instanceof Type.TypeArray arrayType) { + newExpr.type = newExpr.typeExpr.type; + } + else + throw new CompilerException("Unsupported type in new expression"); + return this; + } + + @Override + public ASTVisitor visit(AST.InitExpr initExpr, boolean enter) { + if (enter) + return this; + if (initExpr.newExpr.type == null) + throw new CompilerException("Unresolved type in new expression"); + validType(initExpr.newExpr.type, false); + if (initExpr.newExpr.type instanceof Type.TypeNullable) + throw new CompilerException("new cannot be used to create a Nullable type"); + if (initExpr.newExpr.type instanceof Type.TypeStruct typeStruct) { + for (AST.Expr expr: initExpr.initExprList) { if (expr instanceof AST.SetFieldExpr setFieldExpr) { - setFieldExpr.objectType = newExpr.typeExpr.type; var fieldType = typeStruct.getField(setFieldExpr.fieldName); checkAssignmentCompatible(fieldType, setFieldExpr.value.type); } } } - else if (newExpr.typeExpr.type instanceof Type.TypeArray arrayType) { - newExpr.type = newExpr.typeExpr.type; - for (AST.Expr expr: newExpr.initExprList) { + else if (initExpr.newExpr.type instanceof Type.TypeArray arrayType) { + for (AST.Expr expr: initExpr.initExprList) { checkAssignmentCompatible(arrayType.getElementType(), expr.type); } } else throw new CompilerException("Unsupported type in new expression"); + initExpr.type = initExpr.newExpr.type; return this; } diff --git a/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaDefineTypes.java b/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaDefineTypes.java index f0bf0c6..e5d3498 100644 --- a/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaDefineTypes.java +++ b/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaDefineTypes.java @@ -139,17 +139,17 @@ public ASTVisitor visit(AST.UnaryExpr unaryExpr, boolean enter) { } @Override - public ASTVisitor visit(AST.FieldExpr fieldExpr, boolean enter) { + public ASTVisitor visit(AST.GetFieldExpr fieldExpr, boolean enter) { return this; } @Override - public ASTVisitor visit(AST.CallExpr callExpr, boolean enter) { + public ASTVisitor visit(AST.SetFieldExpr fieldExpr, boolean enter) { return this; } @Override - public ASTVisitor visit(AST.SetFieldExpr setFieldExpr, boolean enter) { + public ASTVisitor visit(AST.CallExpr callExpr, boolean enter) { return this; } @@ -249,7 +249,12 @@ public ASTVisitor visit(AST.LiteralExpr literalExpr, boolean enter) { } @Override - public ASTVisitor visit(AST.ArrayIndexExpr arrayIndexExpr, boolean enter) { + public ASTVisitor visit(AST.ArrayLoadExpr arrayLoadExpr, boolean enter) { + return this; + } + + @Override + public ASTVisitor visit(AST.ArrayStoreExpr arrayStoreExpr, boolean enter) { return this; } @@ -258,6 +263,11 @@ public ASTVisitor visit(AST.NewExpr newExpr, boolean enter) { return this; } + @Override + public ASTVisitor visit(AST.InitExpr initExpr, boolean enter) { + return this; + } + @Override public ASTVisitor visit(AST.NameExpr nameExpr, boolean enter) { return this; diff --git a/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index 209ba60..7be5198 100644 --- a/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -84,6 +84,7 @@ private void compileStatement(AST.Stmt statement) { case AST.VarStmt letStmt -> { compileLet(letStmt); } + case AST.VarDeclStmt varDeclStmt -> {} case AST.IfElseStmt ifElseStmt -> { compileIf(ifElseStmt); } @@ -146,14 +147,14 @@ private void compileBreak(AST.BreakStmt breakStmt) { } private void compileWhile(AST.WhileStmt whileStmt) { - BasicBlock loopBlock = createLoopHead(); + BasicBlock loopHead = createLoopHead(); BasicBlock bodyBlock = createBlock(); BasicBlock exitBlock = createBlock(); BasicBlock savedBreakTarget = currentBreakTarget; BasicBlock savedContinueTarget = currentContinueTarget; currentBreakTarget = exitBlock; - currentContinueTarget = loopBlock; - startBlock(loopBlock); + currentContinueTarget = loopHead; + startBlock(loopHead); boolean indexed = compileExpr(whileStmt.condition); if (indexed) codeIndexedLoad(); @@ -161,7 +162,7 @@ private void compileWhile(AST.WhileStmt whileStmt) { startBlock(bodyBlock); compileStatement(whileStmt.stmt); if (!isBlockTerminated(currentBlock)) - jumpTo(loopBlock); + jumpTo(loopHead); startBlock(exitBlock); currentContinueTarget = savedContinueTarget; currentBreakTarget = savedBreakTarget; @@ -173,6 +174,7 @@ private boolean isBlockTerminated(BasicBlock block) { } private void jumpTo(BasicBlock block) { + assert !isBlockTerminated(currentBlock); currentBlock.add(new Instruction.Jump(block)); currentBlock.addSuccessor(block); } @@ -185,15 +187,15 @@ private void startBlock(BasicBlock block) { } private void compileIf(AST.IfElseStmt ifElseStmt) { - BasicBlock ifBlock = createBlock(); + BasicBlock thenBlock = createBlock(); boolean needElse = ifElseStmt.elseStmt != null; BasicBlock elseBlock = needElse ? createBlock() : null; BasicBlock exitBlock = createBlock(); boolean indexed = compileExpr(ifElseStmt.condition); if (indexed) codeIndexedLoad(); - code(new Instruction.ConditionalBranch(currentBlock, ifBlock, needElse ? elseBlock : exitBlock)); - startBlock(ifBlock); + code(new Instruction.ConditionalBranch(currentBlock, thenBlock, needElse ? elseBlock : exitBlock)); + startBlock(thenBlock); compileStatement(ifElseStmt.ifStmt); if (!isBlockTerminated(currentBlock)) jumpTo(exitBlock); @@ -232,11 +234,17 @@ private boolean compileExpr(AST.Expr expr) { case AST.NewExpr newExpr -> { return compileNewExpr(newExpr); } - case AST.ArrayIndexExpr arrayIndexExpr -> { - return compileArrayIndexExpr(arrayIndexExpr); + case AST.InitExpr initExpr -> { + return compileInitExpr(initExpr); } - case AST.FieldExpr fieldExpr -> { - return compileFieldExpr(fieldExpr); + case AST.ArrayLoadExpr arrayLoadExpr -> { + return compileArrayIndexExpr(arrayLoadExpr); + } + case AST.ArrayStoreExpr arrayStoreExpr -> { + return compileArrayStoreExpr(arrayStoreExpr); + } + case AST.GetFieldExpr getFieldExpr -> { + return compileFieldExpr(getFieldExpr); } case AST.SetFieldExpr setFieldExpr -> { return compileSetFieldExpr(setFieldExpr); @@ -271,7 +279,7 @@ else if (t instanceof Type.TypeNullable ptr && throw new CompilerException("Unexpected type: " + t); } - private boolean compileFieldExpr(AST.FieldExpr fieldExpr) { + private boolean compileFieldExpr(AST.GetFieldExpr fieldExpr) { Type.TypeStruct typeStruct = getStructType(fieldExpr.object.type); int fieldIndex = typeStruct.getFieldIndex(fieldExpr.fieldName); if (fieldIndex < 0) @@ -283,7 +291,7 @@ private boolean compileFieldExpr(AST.FieldExpr fieldExpr) { return true; } - private boolean compileArrayIndexExpr(AST.ArrayIndexExpr arrayIndexExpr) { + private boolean compileArrayIndexExpr(AST.ArrayLoadExpr arrayIndexExpr) { compileExpr(arrayIndexExpr.array); boolean indexed = compileExpr(arrayIndexExpr.expr); if (indexed) @@ -292,10 +300,12 @@ private boolean compileArrayIndexExpr(AST.ArrayIndexExpr arrayIndexExpr) { } private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { - Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.objectType; + Type.TypeStruct structType = (Type.TypeStruct) setFieldExpr.object.type; int fieldIndex = structType.getFieldIndex(setFieldExpr.fieldName); if (fieldIndex == -1) throw new CompilerException("Field " + setFieldExpr.fieldName + " not found in struct " + structType.name); + if (!(setFieldExpr instanceof AST.InitFieldExpr)) + compileExpr(setFieldExpr.object); code(new Instruction.PushConst(fieldIndex)); boolean indexed = compileExpr(setFieldExpr.value); if (indexed) @@ -304,22 +314,29 @@ private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { return false; } + private boolean compileArrayStoreExpr(AST.ArrayStoreExpr arrayStoreExpr) { + if (!(arrayStoreExpr instanceof AST.ArrayInitExpr)) + compileExpr(arrayStoreExpr.array); + boolean indexed = compileExpr(arrayStoreExpr.expr); + if (indexed) + codeIndexedLoad(); + indexed = compileExpr(arrayStoreExpr.value); + if (indexed) + codeIndexedLoad(); + codeIndexedStore(); + return false; + } + private boolean compileNewExpr(AST.NewExpr newExpr) { code(new Instruction.New(newExpr.type)); - if (newExpr.initExprList != null && !newExpr.initExprList.isEmpty()) { - if (newExpr.type instanceof Type.TypeArray) { - for (AST.Expr expr : newExpr.initExprList) { - // Maybe have specific AST similar to how we have SetFieldExpr? - boolean indexed = compileExpr(expr); - if (indexed) - codeIndexedLoad(); - code(new Instruction.StoreAppend()); - } - } - else if (newExpr.type instanceof Type.TypeStruct) { - for (AST.Expr expr : newExpr.initExprList) { - compileExpr(expr); - } + return false; + } + + private boolean compileInitExpr(AST.InitExpr initExpr) { + compileExpr(initExpr.newExpr); + if (initExpr.initExprList != null && !initExpr.initExprList.isEmpty()) { + for (AST.Expr expr : initExpr.initExprList) { + compileExpr(expr); } } return false; diff --git a/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index bc195ef..7fd42cd 100644 --- a/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java +++ b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -18,19 +18,18 @@ public class Instruction { public static final int LOAD_VAR = 10; public static final int NEW = 11; public static final int LOAD_INDEXED = 12; - public static final int STORE_APPEND = 13; // array append - public static final int STORE_INDEXED = 14; - public static final int CALL = 15; - public static final int STORE = 16; - public static final int CBR = 17; - public static final int JUMP = 18; - public static final int POP = 19; - public static final int EQ = 20; - public static final int NE = 21; - public static final int LT = 22; - public static final int GT = 23; - public static final int LE = 24; - public static final int GE = 25; + public static final int STORE_INDEXED = 13; + public static final int CALL = 14; + public static final int STORE = 15; + public static final int CBR = 16; + public static final int JUMP = 17; + public static final int POP = 18; + public static final int EQ = 19; + public static final int NE = 20; + public static final int LT = 21; + public static final int GT = 22; + public static final int LE = 23; + public static final int GE = 24; static final String[] opNames = { "ret", @@ -46,7 +45,6 @@ public class Instruction { "load", "new", "loadindexed", - "storeappend", // array append "storeindexed", "call", "store", @@ -141,12 +139,6 @@ public LoadIndexed() { } } - public static class StoreAppend extends Instruction { - public StoreAppend() { - super(STORE_APPEND); - } - } - public static class StoreIndexed extends Instruction { public StoreIndexed() { super(STORE_INDEXED); diff --git a/stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java b/stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java index 2a9a21e..6393090 100644 --- a/stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java +++ b/stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java @@ -228,12 +228,15 @@ func foo()->[Int] { Assert.assertEquals(""" L0: new [Int] + pushi 0 + pushi 1 + storeindexed pushi 1 - storeappend pushi 2 - storeappend + storeindexed + pushi 2 pushi 3 - storeappend + storeindexed jump L1 L1: """, result); @@ -250,8 +253,9 @@ func foo(n: Int) -> [Int] { Assert.assertEquals(""" L0: new [Int] + pushi 0 load 0 - storeappend + storeindexed jump L1 L1: """, result); @@ -294,6 +298,7 @@ func foo(p: Person) -> Person { pushi 0 pushi 10 storeindexed + pop jump L1 L1: """, result); @@ -341,10 +346,12 @@ func foo(array: [Int]) { pushi 0 pushi 1 storeindexed + pop load 0 pushi 1 pushi 2 storeindexed + pop jump L1 L1: """, result);