From d09041afe11c921e464026436f55b69ebe2cee21 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Sat, 29 Mar 2025 11:35:31 +0000 Subject: [PATCH 1/3] #4 test case --- .../ezlang/semantic/TestSemaAssignTypes.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/semantic/src/test/java/com/compilerprogramming/ezlang/semantic/TestSemaAssignTypes.java b/semantic/src/test/java/com/compilerprogramming/ezlang/semantic/TestSemaAssignTypes.java index 91f6700..a317c12 100644 --- a/semantic/src/test/java/com/compilerprogramming/ezlang/semantic/TestSemaAssignTypes.java +++ b/semantic/src/test/java/com/compilerprogramming/ezlang/semantic/TestSemaAssignTypes.java @@ -5,6 +5,7 @@ import com.compilerprogramming.ezlang.parser.Parser; import com.compilerprogramming.ezlang.types.TypeDictionary; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; public class TestSemaAssignTypes { @@ -420,4 +421,20 @@ func foo() """; analyze(src, "foo", "func foo()"); } + + @Ignore + @Test(expected = CompilerException.class) + public void test23() { + String src = """ + func bar(arg: Int)->Int { + if (arg) + return 42; + return 0; + } + func foo()->Int { + return bar(); + } +"""; + analyze(src, "foo", "func foo()->Int"); + } } From 23ab1b10630ae85f869735c3ad4a21df5ed54eed Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Sat, 29 Mar 2025 11:36:31 +0000 Subject: [PATCH 2/3] Fixes and refactor --- .../ezlang/compiler/CompiledFunction.java | 13 ++----------- .../com/compilerprogramming/ezlang/parser/AST.java | 11 ++++++----- .../compilerprogramming/ezlang/parser/Parser.java | 5 ++++- .../ezlang/compiler/CompiledFunction.java | 13 ++----------- .../ezlang/compiler/Compiler.java | 11 ++++------- .../compilerprogramming/ezlang/compiler/Simple.java | 2 +- .../ezlang/semantic/SemaAssignTypes.java | 4 ++-- .../ezlang/compiler/CompiledFunction.java | 13 ++----------- 8 files changed, 23 insertions(+), 49 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 5d237e0..19a4818 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -175,20 +175,11 @@ private void compileStatement(AST.Stmt statement) { } private void compileAssign(AST.AssignStmt assignStmt) { - boolean indexedLhs = false; - if (!(assignStmt.lhs instanceof AST.NameExpr)) - indexedLhs = compileExpr(assignStmt.lhs); boolean indexedRhs = compileExpr(assignStmt.rhs); if (indexedRhs) codeIndexedLoad(); - if (indexedLhs) - codeIndexedStore(); - else if (assignStmt.lhs instanceof AST.NameExpr symbolExpr) { - Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; - codeMove(pop(), new Operand.LocalRegisterOperand(registerPool.getReg(varSymbol.regNumber), varSymbol)); - } - else - throw new CompilerException("Invalid assignment expression: " + assignStmt.lhs); + Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) assignStmt.nameExpr.symbol; + codeMove(pop(), new Operand.LocalRegisterOperand(registerPool.getReg(varSymbol.regNumber), varSymbol)); } private void compileExprStmt(AST.ExprStmt exprStmt) { 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 1fbb4f7..81a0015 100644 --- a/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java +++ b/parser/src/main/java/com/compilerprogramming/ezlang/parser/AST.java @@ -731,16 +731,17 @@ public void accept(ASTVisitor visitor) { } } + /* name = value */ public static class AssignStmt extends Stmt { - public final Expr lhs; + public final NameExpr nameExpr; public final Expr rhs; - public AssignStmt(Expr lhs, Expr rhs) { - this.lhs = lhs; + public AssignStmt(NameExpr nameExpr, Expr rhs) { + this.nameExpr = nameExpr; this.rhs = rhs; } @Override public StringBuilder toStr(StringBuilder sb) { - lhs.toStr(sb); + nameExpr.toStr(sb); sb.append(" = "); rhs.toStr(sb); return sb; @@ -751,7 +752,7 @@ public void accept(ASTVisitor visitor) { visitor = visitor.visit(this, true); if (visitor == null) return; - lhs.accept(visitor); + nameExpr.accept(visitor); rhs.accept(visitor); visitor.visit(this, false); } 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 f7b4951..0d95fcb 100644 --- a/parser/src/main/java/com/compilerprogramming/ezlang/parser/Parser.java +++ b/parser/src/main/java/com/compilerprogramming/ezlang/parser/Parser.java @@ -253,8 +253,11 @@ private AST.Stmt parseAssign(Lexer lexer) { else if (lhs instanceof AST.GetFieldExpr getFieldExpr) { return new AST.ExprStmt(new AST.SetFieldExpr(getFieldExpr.object, getFieldExpr.fieldName, rhs)); } + else if (lhs instanceof AST.NameExpr nameExpr) { + return new AST.AssignStmt(nameExpr, rhs); + } + else throw new CompilerException("Expected a name, expr[] or expr.field"); } - return new AST.AssignStmt(lhs, rhs); } private AST.Expr parseBool(Lexer lexer) { 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 0e25924..9433d5c 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -139,20 +139,11 @@ private void compileStatement(AST.Stmt statement) { } private void compileAssign(AST.AssignStmt assignStmt) { - boolean indexedLhs = false; - if (!(assignStmt.lhs instanceof AST.NameExpr)) - indexedLhs = compileExpr(assignStmt.lhs); boolean indexedRhs = compileExpr(assignStmt.rhs); if (indexedRhs) codeIndexedLoad(); - if (indexedLhs) - codeIndexedStore(); - else if (assignStmt.lhs instanceof AST.NameExpr symbolExpr) { - Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; - code(new Instruction.Move(pop(), new Operand.LocalRegisterOperand(varSymbol.regNumber, varSymbol.name))); - } - else - throw new CompilerException("Invalid assignment expression: " + assignStmt.lhs); + Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) assignStmt.nameExpr.symbol; + code(new Instruction.Move(pop(), new Operand.LocalRegisterOperand(varSymbol.regNumber, varSymbol.name))); } private void compileExprStmt(AST.ExprStmt exprStmt) { diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java index 4798830..e19a453 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -712,7 +712,9 @@ private Node compileStatement(AST.Stmt statement) { case AST.VarStmt letStmt -> { return compileLet(letStmt); } - case AST.VarDeclStmt varDeclStmt -> {} + case AST.VarDeclStmt varDeclStmt -> { + return ZERO; + } case AST.IfElseStmt ifElseStmt -> { return compileIf(ifElseStmt); } @@ -736,7 +738,6 @@ private Node compileStatement(AST.Stmt statement) { } default -> throw new IllegalStateException("Unexpected value: " + statement); } - throw new CompilerException("Not yet implemented"); } private ScopeNode jumpTo(ScopeNode toScope) { @@ -847,7 +848,6 @@ private Node compileWhile(AST.WhileStmt whileStmt) { // At exit the false control is the current control, and // the scope is the exit scope after the exit test. - _xScopes.pop(); _xScopes.push(exit); _scope = exit; return ZERO; @@ -855,8 +855,6 @@ private Node compileWhile(AST.WhileStmt whileStmt) { private Node compileIf(AST.IfElseStmt ifElseStmt) { var pred = compileExpr(ifElseStmt.condition).keep(); - pred.keep(); - // IfNode takes current control and predicate Node ifNode = new IfNode(ctrl(), pred).peephole(); // Setup projection nodes @@ -914,8 +912,7 @@ private Node compileExprStmt(AST.ExprStmt exprStmt) { } private Node compileAssign(AST.AssignStmt assignStmt) { - if (!(assignStmt.lhs instanceof AST.NameExpr nameExpr)) - throw new CompilerException("Assignment requires a nameExpr"); + var nameExpr = assignStmt.nameExpr; String name = nameExpr.name; if (!(nameExpr.symbol instanceof Symbol.VarSymbol varSymbol)) throw new CompilerException("Assignment requires a variable name"); diff --git a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java index eb5c5d2..c649fbd 100644 --- a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java +++ b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/Simple.java @@ -11,7 +11,7 @@ import java.util.stream.Collectors; public class Simple { - public static final String PORTS = "com.seaofnodes.simple.node.cpus"; + public static final String PORTS = "com.compilerprogramming.ezlang.compiler.nodes.cpus"; static final int DUMP_AFTER_PARSE = 1<<0; static final int DUMP_AFTER_OPTO = 1<<1; 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 25abf39..0fa930d 100644 --- a/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaAssignTypes.java +++ b/semantic/src/main/java/com/compilerprogramming/ezlang/semantic/SemaAssignTypes.java @@ -385,9 +385,9 @@ public ASTVisitor visit(AST.ExprStmt exprStmt, boolean enter) { @Override public ASTVisitor visit(AST.AssignStmt assignStmt, boolean enter) { if (!enter) { - validType(assignStmt.lhs.type, false); + validType(assignStmt.nameExpr.type, false); validType(assignStmt.rhs.type, true); - checkAssignmentCompatible(assignStmt.lhs.type, assignStmt.rhs.type); + checkAssignmentCompatible(assignStmt.nameExpr.type, assignStmt.rhs.type); } 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 7be5198..ed83aca 100644 --- a/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -111,20 +111,11 @@ private void compileStatement(AST.Stmt statement) { } private void compileAssign(AST.AssignStmt assignStmt) { - boolean indexedLhs = false; - if (!(assignStmt.lhs instanceof AST.NameExpr)) - indexedLhs = compileExpr(assignStmt.lhs); boolean indexedRhs = compileExpr(assignStmt.rhs); if (indexedRhs) codeIndexedLoad(); - if (indexedLhs) - codeIndexedStore(); - else if (assignStmt.lhs instanceof AST.NameExpr symbolExpr) { - Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; - code(new Instruction.Store(varSymbol.regNumber)); - } - else - throw new CompilerException("Invalid assignment expression: " + assignStmt.lhs); + Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) assignStmt.nameExpr.symbol; + code(new Instruction.Store(varSymbol.regNumber)); } private void compileExprStmt(AST.ExprStmt exprStmt) { From fd1ae26fbcea33f1a15129203819f7efd178dc39 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Sat, 29 Mar 2025 22:47:24 +0000 Subject: [PATCH 3/3] Bug fix --- .../ezlang/interpreter/Interpreter.java | 8 +- .../ezlang/interpreter/Interpreter.java | 8 +- .../ezlang/interpreter/TestInterpreter.java | 88 +++++++++++++++++++ 3 files changed, 96 insertions(+), 8 deletions(-) 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 66de388..c85fa24 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -108,13 +108,13 @@ else if (cbrInst.condition() instanceof Operand.ConstantOperand constantOperand) int reg = baseReg; for (Operand arg: callInst.args()) { if (arg instanceof Operand.RegisterOperand param) { - execStack.stack[base + reg] = execStack.stack[base + param.frameSlot()]; + execStack.stack[reg] = execStack.stack[base + param.frameSlot()]; } else if (arg instanceof Operand.ConstantOperand constantOperand) { - execStack.stack[base + reg] = new Value.IntegerValue(constantOperand.value); + execStack.stack[reg] = new Value.IntegerValue(constantOperand.value); } else if (arg instanceof Operand.NullConstantOperand) { - execStack.stack[base + reg] = new Value.NullValue(); + execStack.stack[reg] = new Value.NullValue(); } reg += 1; } @@ -193,7 +193,7 @@ else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand) case "<": value = x < y ? 1: 0; break; case ">": value = x > y ? 1 : 0; break; case "<=": value = x <= y ? 1 : 0; break; - case ">=": value = x <= y ? 1 : 0; break; + case ">=": value = x >= y ? 1 : 0; break; default: throw new IllegalStateException(); } execStack.stack[base + binaryInst.result().frameSlot()] = new Value.IntegerValue(value); 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 7771700..919a82e 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -108,13 +108,13 @@ else if (cbrInst.condition() instanceof Operand.ConstantOperand constantOperand) int reg = baseReg; for (Operand arg: callInst.args()) { if (arg instanceof Operand.RegisterOperand param) { - execStack.stack[base + reg] = execStack.stack[base + param.frameSlot()]; + execStack.stack[reg] = execStack.stack[base + param.frameSlot()]; } else if (arg instanceof Operand.ConstantOperand constantOperand) { - execStack.stack[base + reg] = new Value.IntegerValue(constantOperand.value); + execStack.stack[reg] = new Value.IntegerValue(constantOperand.value); } else if (arg instanceof Operand.NullConstantOperand) { - execStack.stack[base + reg] = new Value.NullValue(); + execStack.stack[reg] = new Value.NullValue(); } reg += 1; } @@ -193,7 +193,7 @@ else if (binaryInst.right() instanceof Operand.RegisterOperand registerOperand) case "<": value = x < y ? 1: 0; break; case ">": value = x > y ? 1 : 0; break; case "<=": value = x <= y ? 1 : 0; break; - case ">=": value = x <= y ? 1 : 0; break; + case ">=": value = x >= y ? 1 : 0; break; default: throw new IllegalStateException(); } execStack.stack[base + binaryInst.result().frameSlot()] = new Value.IntegerValue(value); diff --git a/registervm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java b/registervm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java index fcb93e2..78e4d48 100644 --- a/registervm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java +++ b/registervm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java @@ -244,4 +244,92 @@ func foo()->Int Assert.assertTrue(value instanceof Value.IntegerValue integerValue && integerValue.value == 1); } + + @Test + public void testMergeSort() { + String src = """ +// based on the top-down version from https://en.wikipedia.org/wiki/Merge_sort +// via https://github.com/SeaOfNodes/Simple +func merge_sort(a: [Int], b: [int], n: Int) +{ + copy_array(a, 0, n, b) + split_merge(a, 0, n, b) +} + +func split_merge(b: [Int], begin: Int, end: Int, a: [Int]) +{ + if (end - begin <= 1) + return; + var middle = (end + begin) / 2 + split_merge(a, begin, middle, b) + split_merge(a, middle, end, b) + merge(b, begin, middle, end, a) +} + +func merge(b: [Int], begin: Int, middle: Int, end: Int, a: [Int]) +{ + var i = begin + var j = middle + var k = begin + while (k < end) { + // && and || + var cond = 0 + if (i < middle) { + if (j >= end) cond = 1; + else if (a[i] <= a[j]) cond = 1; + } + if (cond) + { + b[k] = a[i] + i = i + 1 + } + else + { + b[k] = a[j] + j = j + 1 + } + k = k + 1 + } +} + +func copy_array(a: [Int], begin: Int, end: Int, b: [Int]) +{ + var k = begin + while (k < end) + { + b[k] = a[k] + k = k + 1 + } +} + +func eq(a: [Int], b: [Int], n: Int)->Int +{ + var result = 1 + var i = 0 + while (i < n) + { + if (a[i] != b[i]) + { + result = 0 + break + } + i = i + 1 + } + return result +} + +func main()->Int +{ + var a = new [Int]{10,9,8,7,6,5,4,3,2,1} + var b = new [Int]{ 0,0,0,0,0,0,0,0,0,0} + var expect = new [Int]{1,2,3,4,5,6,7,8,9,10} + merge_sort(a, b, 10) + return eq(a,expect,10) +} +"""; + var value = compileAndRun(src, "main"); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue && + integerValue.value == 1); + } }