From eee8f6492f05d32a5b874f175edb277a7294ee69 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Sat, 14 Dec 2024 00:07:31 +0000 Subject: [PATCH] Tech debt Tech debt Rename bytecode package to compiler Some more renaming Fix expected results for tests copied from registervm Update README --- README.md | 10 +- .../ezlang/bytecode/BytecodeCompiler.java | 17 - .../{bytecode => compiler}/BasicBlock.java | 2 +- .../CompiledFunction.java} | 6 +- .../ezlang/compiler/Compiler.java | 45 ++ .../{bytecode => compiler}/DominatorTree.java | 2 +- .../{bytecode => compiler}/Instruction.java | 2 +- .../{bytecode => compiler}/LoopFinder.java | 2 +- .../{bytecode => compiler}/LoopNest.java | 2 +- .../{bytecode => compiler}/Operand.java | 2 +- .../{bytecode => compiler}/SSATransform.java | 6 +- .../ezlang/interpreter/Interpreter.java | 16 +- .../{bytecode => compiler}/TestCompiler.java | 30 +- .../TestDominators.java | 2 +- .../TestSSATransform.java | 20 +- .../TestInterpreter.java | 34 +- .../ezlang/bytecode/BytecodeCompiler.java | 17 - .../{bytecode => compiler}/BasicBlock.java | 3 +- .../CompiledFunction.java} | 10 +- .../ezlang/compiler/Compiler.java | 44 ++ .../{bytecode => compiler}/Instruction.java | 2 +- .../{bytecode => compiler}/Operand.java | 2 +- .../ezlang/interpreter/Interpreter.java | 16 +- .../{bytecode => compiler}/TestCompiler.java | 30 +- .../TestInterpreter.java | 34 +- .../ezlang/bytecode/ByteCodeCompiler.java | 17 - .../{bytecode => compiler}/BasicBlock.java | 6 +- .../CompiledFunction.java} | 65 +- .../ezlang/compiler/Compiler.java | 44 ++ .../{bytecode => compiler}/Instruction.java | 2 +- .../ezlang/bytecode/TestCompiler.java | 290 -------- .../ezlang/compiler/TestCompiler.java | 630 ++++++++++++++++++ 32 files changed, 876 insertions(+), 534 deletions(-) delete mode 100644 optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/BasicBlock.java (98%) rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode/BytecodeFunction.java => compiler/CompiledFunction.java} (99%) create mode 100644 optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/DominatorTree.java (99%) rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/Instruction.java (99%) rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/LoopFinder.java (98%) rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/LoopNest.java (97%) rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/Operand.java (98%) rename optvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/SSATransform.java (98%) rename optvm/src/test/java/com/compilerprogramming/ezlang/{bytecode => compiler}/TestCompiler.java (90%) rename optvm/src/test/java/com/compilerprogramming/ezlang/{bytecode => compiler}/TestDominators.java (98%) rename optvm/src/test/java/com/compilerprogramming/ezlang/{bytecode => compiler}/TestSSATransform.java (89%) rename optvm/src/test/java/com/compilerprogramming/ezlang/{bytecode => interpreter}/TestInterpreter.java (69%) delete mode 100644 registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java rename registervm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/BasicBlock.java (96%) rename registervm/src/main/java/com/compilerprogramming/ezlang/{bytecode/BytecodeFunction.java => compiler/CompiledFunction.java} (99%) create mode 100644 registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java rename registervm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/Instruction.java (99%) rename registervm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/Operand.java (98%) rename registervm/src/test/java/com/compilerprogramming/ezlang/{bytecode => compiler}/TestCompiler.java (92%) rename registervm/src/test/java/com/compilerprogramming/ezlang/{bytecode => interpreter}/TestInterpreter.java (69%) delete mode 100644 stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/ByteCodeCompiler.java rename stackvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/BasicBlock.java (85%) rename stackvm/src/main/java/com/compilerprogramming/ezlang/{bytecode/BytecodeFunction.java => compiler/CompiledFunction.java} (91%) create mode 100644 stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java rename stackvm/src/main/java/com/compilerprogramming/ezlang/{bytecode => compiler}/Instruction.java (99%) delete mode 100644 stackvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java create mode 100644 stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java diff --git a/README.md b/README.md index 4b94011..6307032 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,14 @@ The project is under development and subject to change. At this point in time, w ## How can you contribute? -Obviously firstly any contributions that improve the implementation and/or fix bugs are welcome. I am not keen on language extensions at this stage, but eventually -we will be extending the language to explore more advanced features. +The project is educational, with a focus on exploring various compiler algorithms and data structures. +Clarity and simplicity is preferred over a coding style that attempts to do micro optimizations. -I am also interested in creating implementations of this project in C++, Go, Rust, Swift, D, C, etc. If you are interested in working on such a +Contributions that improve the quality of the implementation, add test cases / documentation or fix bugs, are very welcome. +I am not keen on language extensions at this stage, but eventually we will be extending the language to explore more +advanced features. + +I am also interested in porting this project to C++, Go, Rust, Swift, D, C, etc. If you are interested in working on such a port please contact me via [Discussions](https://github.com/orgs/CompilerProgramming/discussions). ## Community Discussions diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java b/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java deleted file mode 100644 index 3bef310..0000000 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.compilerprogramming.ezlang.bytecode; - -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; -import com.compilerprogramming.ezlang.types.TypeDictionary; - -public class BytecodeCompiler { - - public void compile(TypeDictionary typeDictionary) { - for (Symbol symbol: typeDictionary.getLocalSymbols()) { - if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { - Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; - functionType.code = new BytecodeFunction(functionSymbol); - } - } - } -} diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java similarity index 98% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java index 41293df..e163a44 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Register; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java similarity index 99% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index dfdfdff..63f94eb 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.exceptions.CompilerException; import com.compilerprogramming.ezlang.parser.AST; @@ -10,7 +10,7 @@ import java.util.ArrayList; import java.util.List; -public class BytecodeFunction { +public class CompiledFunction { public BasicBlock entry; public BasicBlock exit; @@ -41,7 +41,7 @@ public class BytecodeFunction { */ private List virtualStack = new ArrayList<>(); - public BytecodeFunction(Symbol.FunctionTypeSymbol functionSymbol) { + public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol) { AST.FuncDecl funcDecl = (AST.FuncDecl) functionSymbol.functionDecl; setVirtualRegisters(funcDecl.scope); this.numLocalRegs = this.nextReg; // Before assigning temps diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java new file mode 100644 index 0000000..aa173b7 --- /dev/null +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -0,0 +1,45 @@ +package com.compilerprogramming.ezlang.compiler; + +import com.compilerprogramming.ezlang.lexer.Lexer; +import com.compilerprogramming.ezlang.parser.Parser; +import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; +import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; +import com.compilerprogramming.ezlang.types.Symbol; +import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.TypeDictionary; + +import java.util.BitSet; + +public class Compiler { + + private void compile(TypeDictionary typeDictionary) { + for (Symbol symbol: typeDictionary.getLocalSymbols()) { + if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { + Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; + functionType.code = new CompiledFunction(functionSymbol); + } + } + } + public TypeDictionary compileSrc(String src) { + Parser parser = new Parser(); + var program = parser.parse(new Lexer(src)); + var typeDict = new TypeDictionary(); + var sema = new SemaDefineTypes(typeDict); + sema.analyze(program); + var sema2 = new SemaAssignTypes(typeDict); + sema2.analyze(program); + compile(typeDict); + return typeDict; + } + public String dumpIR(TypeDictionary typeDictionary) { + StringBuilder sb = new StringBuilder(); + for (Symbol s: typeDictionary.bindings.values()) { + if (s instanceof Symbol.FunctionTypeSymbol f) { + var functionBuilder = (CompiledFunction) f.code(); + BasicBlock.toStr(sb, functionBuilder.entry, new BitSet()); + } + } + return sb.toString(); + } + +} diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/DominatorTree.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/DominatorTree.java similarity index 99% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/DominatorTree.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/DominatorTree.java index ec13103..21f68a9 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/DominatorTree.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/DominatorTree.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import java.util.ArrayList; import java.util.Comparator; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java similarity index 99% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index 26a4326..e6e4a3d 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Register; import com.compilerprogramming.ezlang.types.Type; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/LoopFinder.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/LoopFinder.java similarity index 98% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/LoopFinder.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/LoopFinder.java index 313bde4..ce487a0 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/LoopFinder.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/LoopFinder.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import java.util.*; import java.util.stream.Collectors; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/LoopNest.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/LoopNest.java similarity index 97% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/LoopNest.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/LoopNest.java index 1aeca0a..b7ab51d 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/LoopNest.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/LoopNest.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import java.util.*; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Operand.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java similarity index 98% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Operand.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java index 90e481d..ee38140 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Operand.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Register; import com.compilerprogramming.ezlang.types.Type; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/SSATransform.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SSATransform.java similarity index 98% rename from optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/SSATransform.java rename to optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SSATransform.java index 3ff81cf..2cc84e0 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/bytecode/SSATransform.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SSATransform.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Register; @@ -9,7 +9,7 @@ */ public class SSATransform { - BytecodeFunction function; + CompiledFunction function; DominatorTree domTree; Register[] globals; BBSet[] blockSets; @@ -17,7 +17,7 @@ public class SSATransform { int[] counters; VersionStack[] stacks; - public SSATransform(BytecodeFunction bytecodeFunction) { + public SSATransform(CompiledFunction bytecodeFunction) { this.function = bytecodeFunction; setupGlobals(); computeDomTreeAndDominanceFrontiers(); 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 3e48b71..ef7c90a 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -1,9 +1,9 @@ package com.compilerprogramming.ezlang.interpreter; -import com.compilerprogramming.ezlang.bytecode.BasicBlock; -import com.compilerprogramming.ezlang.bytecode.BytecodeFunction; -import com.compilerprogramming.ezlang.bytecode.Instruction; -import com.compilerprogramming.ezlang.bytecode.Operand; +import com.compilerprogramming.ezlang.compiler.BasicBlock; +import com.compilerprogramming.ezlang.compiler.CompiledFunction; +import com.compilerprogramming.ezlang.compiler.Instruction; +import com.compilerprogramming.ezlang.compiler.Operand; import com.compilerprogramming.ezlang.exceptions.CompilerException; import com.compilerprogramming.ezlang.exceptions.InterpreterException; import com.compilerprogramming.ezlang.types.Symbol; @@ -31,7 +31,7 @@ public Value run(String functionName) { } public Value interpret(ExecutionStack execStack, Frame frame) { - BytecodeFunction currentFunction = frame.bytecodeFunction; + CompiledFunction currentFunction = frame.bytecodeFunction; BasicBlock currentBlock = currentFunction.entry; int ip = -1; int base = frame.base; @@ -239,18 +239,18 @@ else if (setFieldInst.sourceOperand instanceof Operand.RegisterOperand registerO static class Frame { Frame caller; int base; - BytecodeFunction bytecodeFunction; + CompiledFunction bytecodeFunction; public Frame(Symbol.FunctionTypeSymbol functionSymbol) { this.caller = null; this.base = 0; - this.bytecodeFunction = (BytecodeFunction) functionSymbol.code(); + this.bytecodeFunction = (CompiledFunction) functionSymbol.code(); } Frame(Frame caller, int base, Type.TypeFunction functionType) { this.caller = caller; this.base = base; - this.bytecodeFunction = (BytecodeFunction) functionType.code; + this.bytecodeFunction = (CompiledFunction) functionType.code; } } } diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java similarity index 90% rename from optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java rename to optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java index 4401d4b..047e8a3 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java @@ -1,36 +1,14 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; -import com.compilerprogramming.ezlang.lexer.Lexer; -import com.compilerprogramming.ezlang.parser.Parser; -import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; -import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.TypeDictionary; import org.junit.Assert; import org.junit.Test; -import java.util.BitSet; - public class TestCompiler { String compileSrc(String src) { - Parser parser = new Parser(); - var program = parser.parse(new Lexer(src)); - var typeDict = new TypeDictionary(); - var sema = new SemaDefineTypes(typeDict); - sema.analyze(program); - var sema2 = new SemaAssignTypes(typeDict); - sema2.analyze(program); - var byteCodeCompiler = new BytecodeCompiler(); - byteCodeCompiler.compile(typeDict); - StringBuilder sb = new StringBuilder(); - for (Symbol s : typeDict.bindings.values()) { - if (s instanceof Symbol.FunctionTypeSymbol f) { - var functionBuilder = (BytecodeFunction) f.code(); - BasicBlock.toStr(sb, functionBuilder.entry, new BitSet()); - } - } - return sb.toString(); + var compiler = new Compiler(); + var typeDict = compiler.compileSrc(src); + return compiler.dumpIR(typeDict); } @Test diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestDominators.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestDominators.java similarity index 98% rename from optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestDominators.java rename to optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestDominators.java index 293bd72..4a74ded 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestDominators.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestDominators.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import org.junit.Assert; import org.junit.Test; diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestSSATransform.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java similarity index 89% rename from optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestSSATransform.java rename to optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java index 70b82fe..4adef51 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestSSATransform.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java @@ -1,11 +1,6 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; -import com.compilerprogramming.ezlang.lexer.Lexer; -import com.compilerprogramming.ezlang.parser.Parser; -import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; -import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.TypeDictionary; import org.junit.Assert; import org.junit.Test; @@ -14,19 +9,12 @@ public class TestSSATransform { String compileSrc(String src) { - Parser parser = new Parser(); - var program = parser.parse(new Lexer(src)); - var typeDict = new TypeDictionary(); - var sema = new SemaDefineTypes(typeDict); - sema.analyze(program); - var sema2 = new SemaAssignTypes(typeDict); - sema2.analyze(program); - var byteCodeCompiler = new BytecodeCompiler(); - byteCodeCompiler.compile(typeDict); + var compiler = new Compiler(); + var typeDict = compiler.compileSrc(src); StringBuilder sb = new StringBuilder(); for (Symbol s : typeDict.bindings.values()) { if (s instanceof Symbol.FunctionTypeSymbol f) { - var functionBuilder = (BytecodeFunction) f.code(); + var functionBuilder = (CompiledFunction) f.code(); sb.append("func ").append(f.name).append("\n"); sb.append("Before SSA\n"); sb.append("==========\n"); diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestInterpreter.java b/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java similarity index 69% rename from optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestInterpreter.java rename to optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java index a2fdd69..4913352 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestInterpreter.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java @@ -1,38 +1,16 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.interpreter; -import com.compilerprogramming.ezlang.interpreter.Interpreter; -import com.compilerprogramming.ezlang.interpreter.Value; -import com.compilerprogramming.ezlang.lexer.Lexer; -import com.compilerprogramming.ezlang.parser.Parser; -import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; -import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.TypeDictionary; +import com.compilerprogramming.ezlang.compiler.Compiler; import org.junit.Assert; import org.junit.Test; -import java.util.BitSet; - public class TestInterpreter { Value compileAndRun(String src, String mainFunction) { - Parser parser = new Parser(); - var program = parser.parse(new Lexer(src)); - var typeDict = new TypeDictionary(); - var sema = new SemaDefineTypes(typeDict); - sema.analyze(program); - var sema2 = new SemaAssignTypes(typeDict); - sema2.analyze(program); - var byteCodeCompiler = new BytecodeCompiler(); - byteCodeCompiler.compile(typeDict); - StringBuilder sb = new StringBuilder(); - for (Symbol s : typeDict.bindings.values()) { - if (s instanceof Symbol.FunctionTypeSymbol f) { - var functionBuilder = (BytecodeFunction) f.code(); - BasicBlock.toStr(sb, functionBuilder.entry, new BitSet()); - } - } - System.out.println(sb.toString()); + var compiler = new Compiler(); + var typeDict = compiler.compileSrc(src); + var compiled = compiler.dumpIR(typeDict); + System.out.println(compiled); var interpreter = new Interpreter(typeDict); return interpreter.run(mainFunction); } diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java b/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java deleted file mode 100644 index 3bef310..0000000 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeCompiler.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.compilerprogramming.ezlang.bytecode; - -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; -import com.compilerprogramming.ezlang.types.TypeDictionary; - -public class BytecodeCompiler { - - public void compile(TypeDictionary typeDictionary) { - for (Symbol symbol: typeDictionary.getLocalSymbols()) { - if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { - Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; - functionType.code = new BytecodeFunction(functionSymbol); - } - } - } -} diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java similarity index 96% rename from registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java rename to registervm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java index 52bb55d..daba939 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import java.util.ArrayList; import java.util.BitSet; @@ -25,6 +25,7 @@ public void addSuccessor(BasicBlock successor) { successors.add(successor); successor.predecessors.add(this); } + public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visited) { if (visited.get(bb.bid)) diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java similarity index 99% rename from registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java rename to registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index a83a5f8..8dfa509 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.exceptions.CompilerException; import com.compilerprogramming.ezlang.parser.AST; @@ -10,16 +10,16 @@ import java.util.ArrayList; import java.util.List; -public class BytecodeFunction { +public class CompiledFunction { public BasicBlock entry; public BasicBlock exit; - public int maxLocalReg; - public int maxStackSize; private int bid = 0; private BasicBlock currentBlock; private BasicBlock currentBreakTarget; private BasicBlock currentContinueTarget; + public int maxLocalReg; + public int maxStackSize; /** * We essentially do a form of abstract interpretation as we generate @@ -31,7 +31,7 @@ public class BytecodeFunction { */ private List virtualStack = new ArrayList<>(); - public BytecodeFunction(Symbol.FunctionTypeSymbol functionSymbol) { + public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol) { AST.FuncDecl funcDecl = (AST.FuncDecl) functionSymbol.functionDecl; setVirtualRegisters(funcDecl.scope); this.bid = 0; diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java new file mode 100644 index 0000000..5c0b365 --- /dev/null +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -0,0 +1,44 @@ +package com.compilerprogramming.ezlang.compiler; + +import com.compilerprogramming.ezlang.lexer.Lexer; +import com.compilerprogramming.ezlang.parser.Parser; +import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; +import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; +import com.compilerprogramming.ezlang.types.Symbol; +import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.TypeDictionary; + +import java.util.BitSet; + +public class Compiler { + + private void compile(TypeDictionary typeDictionary) { + for (Symbol symbol: typeDictionary.getLocalSymbols()) { + if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { + Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; + functionType.code = new CompiledFunction(functionSymbol); + } + } + } + public TypeDictionary compileSrc(String src) { + Parser parser = new Parser(); + var program = parser.parse(new Lexer(src)); + var typeDict = new TypeDictionary(); + var sema = new SemaDefineTypes(typeDict); + sema.analyze(program); + var sema2 = new SemaAssignTypes(typeDict); + sema2.analyze(program); + compile(typeDict); + return typeDict; + } + public String dumpIR(TypeDictionary typeDictionary) { + StringBuilder sb = new StringBuilder(); + for (Symbol s: typeDictionary.bindings.values()) { + if (s instanceof Symbol.FunctionTypeSymbol f) { + var functionBuilder = (CompiledFunction) f.code(); + BasicBlock.toStr(sb, functionBuilder.entry, new BitSet()); + } + } + return sb.toString(); + } +} diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java similarity index 99% rename from registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java rename to registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index b1e220a..448c0da 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Type; diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/Operand.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java similarity index 98% rename from registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/Operand.java rename to registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java index 6ff8248..bff7d66 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/bytecode/Operand.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/Operand.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Type; 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 46c0b65..3c06472 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/interpreter/Interpreter.java @@ -1,9 +1,9 @@ package com.compilerprogramming.ezlang.interpreter; -import com.compilerprogramming.ezlang.bytecode.BasicBlock; -import com.compilerprogramming.ezlang.bytecode.BytecodeFunction; -import com.compilerprogramming.ezlang.bytecode.Instruction; -import com.compilerprogramming.ezlang.bytecode.Operand; +import com.compilerprogramming.ezlang.compiler.BasicBlock; +import com.compilerprogramming.ezlang.compiler.CompiledFunction; +import com.compilerprogramming.ezlang.compiler.Instruction; +import com.compilerprogramming.ezlang.compiler.Operand; import com.compilerprogramming.ezlang.exceptions.CompilerException; import com.compilerprogramming.ezlang.exceptions.InterpreterException; import com.compilerprogramming.ezlang.types.Symbol; @@ -31,7 +31,7 @@ public Value run(String functionName) { } public Value interpret(ExecutionStack execStack, Frame frame) { - BytecodeFunction currentFunction = frame.bytecodeFunction; + CompiledFunction currentFunction = frame.bytecodeFunction; BasicBlock currentBlock = currentFunction.entry; int ip = -1; int base = frame.base; @@ -238,18 +238,18 @@ else if (setFieldInst.sourceOperand instanceof Operand.RegisterOperand registerO static class Frame { Frame caller; int base; - BytecodeFunction bytecodeFunction; + CompiledFunction bytecodeFunction; public Frame(Symbol.FunctionTypeSymbol functionSymbol) { this.caller = null; this.base = 0; - this.bytecodeFunction = (BytecodeFunction) functionSymbol.code(); + this.bytecodeFunction = (CompiledFunction) functionSymbol.code(); } Frame(Frame caller, int base, Type.TypeFunction functionType) { this.caller = caller; this.base = base; - this.bytecodeFunction = (BytecodeFunction) functionType.code; + this.bytecodeFunction = (CompiledFunction) functionType.code; } } } diff --git a/registervm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java b/registervm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java similarity index 92% rename from registervm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java rename to registervm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java index f9fbc74..294d6ac 100644 --- a/registervm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java +++ b/registervm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java @@ -1,36 +1,14 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; -import com.compilerprogramming.ezlang.lexer.Lexer; -import com.compilerprogramming.ezlang.parser.Parser; -import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; -import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.TypeDictionary; import org.junit.Assert; import org.junit.Test; -import java.util.BitSet; - public class TestCompiler { String compileSrc(String src) { - Parser parser = new Parser(); - var program = parser.parse(new Lexer(src)); - var typeDict = new TypeDictionary(); - var sema = new SemaDefineTypes(typeDict); - sema.analyze(program); - var sema2 = new SemaAssignTypes(typeDict); - sema2.analyze(program); - BytecodeCompiler byteCodeCompiler = new BytecodeCompiler(); - byteCodeCompiler.compile(typeDict); - StringBuilder sb = new StringBuilder(); - for (Symbol s: typeDict.bindings.values()) { - if (s instanceof Symbol.FunctionTypeSymbol f) { - var functionBuilder = (BytecodeFunction) f.code(); - BasicBlock.toStr(sb, functionBuilder.entry, new BitSet()); - } - } - return sb.toString(); + var compiler = new Compiler(); + var typeDict = compiler.compileSrc(src); + return compiler.dumpIR(typeDict); } @Test diff --git a/registervm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestInterpreter.java b/registervm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java similarity index 69% rename from registervm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestInterpreter.java rename to registervm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java index 15c1257..4913352 100644 --- a/registervm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestInterpreter.java +++ b/registervm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java @@ -1,38 +1,16 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.interpreter; -import com.compilerprogramming.ezlang.interpreter.Interpreter; -import com.compilerprogramming.ezlang.interpreter.Value; -import com.compilerprogramming.ezlang.lexer.Lexer; -import com.compilerprogramming.ezlang.parser.Parser; -import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; -import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.TypeDictionary; +import com.compilerprogramming.ezlang.compiler.Compiler; import org.junit.Assert; import org.junit.Test; -import java.util.BitSet; - public class TestInterpreter { Value compileAndRun(String src, String mainFunction) { - Parser parser = new Parser(); - var program = parser.parse(new Lexer(src)); - var typeDict = new TypeDictionary(); - var sema = new SemaDefineTypes(typeDict); - sema.analyze(program); - var sema2 = new SemaAssignTypes(typeDict); - sema2.analyze(program); - BytecodeCompiler byteCodeCompiler = new BytecodeCompiler(); - byteCodeCompiler.compile(typeDict); - StringBuilder sb = new StringBuilder(); - for (Symbol s : typeDict.bindings.values()) { - if (s instanceof Symbol.FunctionTypeSymbol f) { - var functionBuilder = (BytecodeFunction) f.code(); - BasicBlock.toStr(sb, functionBuilder.entry, new BitSet()); - } - } - System.out.println(sb.toString()); + var compiler = new Compiler(); + var typeDict = compiler.compileSrc(src); + var compiled = compiler.dumpIR(typeDict); + System.out.println(compiled); var interpreter = new Interpreter(typeDict); return interpreter.run(mainFunction); } diff --git a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/ByteCodeCompiler.java b/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/ByteCodeCompiler.java deleted file mode 100644 index 85a846a..0000000 --- a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/ByteCodeCompiler.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.compilerprogramming.ezlang.bytecode; - -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.Type; -import com.compilerprogramming.ezlang.types.TypeDictionary; - -public class ByteCodeCompiler { - - public void compile(TypeDictionary typeDictionary) { - for (Symbol symbol: typeDictionary.getLocalSymbols()) { - if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { - Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; - functionType.code = new BytecodeFunction(functionSymbol); - } - } - } -} diff --git a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java similarity index 85% rename from stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java rename to stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java index d1b465e..d95bc99 100644 --- a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BasicBlock.java +++ b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import java.util.ArrayList; import java.util.BitSet; @@ -7,8 +7,8 @@ public class BasicBlock { public final int bid; public final boolean loopHead; - public List successors = new ArrayList<>(); // successors - List predecessors = new ArrayList<>(); + public final List successors = new ArrayList<>(); // successors + public final List predecessors = new ArrayList<>(); public final List instructions = new ArrayList<>(); public BasicBlock(int bid, boolean loopHead) { diff --git a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java similarity index 91% rename from stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java rename to stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index f7d6668..a1a8b61 100644 --- a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/BytecodeFunction.java +++ b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.exceptions.CompilerException; import com.compilerprogramming.ezlang.parser.AST; @@ -7,16 +7,16 @@ import com.compilerprogramming.ezlang.types.Symbol; import com.compilerprogramming.ezlang.types.Type; -public class BytecodeFunction { +public class CompiledFunction { - BasicBlock entry; - BasicBlock exit; - int bid = 0; - BasicBlock currentBlock; - BasicBlock currentBreakTarget; - BasicBlock currentContinueTarget; + public BasicBlock entry; + public BasicBlock exit; + private int bid = 0; + private BasicBlock currentBlock; + private BasicBlock currentBreakTarget; + private BasicBlock currentContinueTarget; - public BytecodeFunction(Symbol.FunctionTypeSymbol functionSymbol) { + public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol) { AST.FuncDecl funcDecl = (AST.FuncDecl) functionSymbol.functionDecl; setVirtualRegisters(funcDecl.scope); this.bid = 0; @@ -25,6 +25,14 @@ public BytecodeFunction(Symbol.FunctionTypeSymbol functionSymbol) { this.currentBreakTarget = null; this.currentContinueTarget = null; compileStatement(funcDecl.block); + exitBlockIfNeeded(); + } + + private void exitBlockIfNeeded() { + if (currentBlock != null && + currentBlock != exit) { + startBlock(exit); + } } private void setVirtualRegisters(Scope scope) { @@ -33,7 +41,7 @@ private void setVirtualRegisters(Scope scope) { reg = scope.parent.maxReg; for (Symbol symbol: scope.getLocalSymbols()) { if (symbol instanceof Symbol.VarSymbol varSymbol) { - varSymbol.reg = new Register(reg, 0, varSymbol.name, varSymbol.type); + varSymbol.reg = new Register(reg++, 0, varSymbol.name, varSymbol.type); } } scope.maxReg = reg; @@ -60,7 +68,7 @@ private void compileReturn(AST.ReturnStmt returnStmt) { if (returnStmt.expr != null) { boolean indexed = compileExpr(returnStmt.expr); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); } jumpTo(exit); } @@ -108,9 +116,9 @@ private void compileAssign(AST.AssignStmt assignStmt) { indexedLhs = compileExpr(assignStmt.lhs); boolean indexedRhs = compileExpr(assignStmt.rhs); if (indexedRhs) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); if (indexedLhs) - code(new Instruction.StoreIndexed()); + codeIndexedStore(); else if (assignStmt.lhs instanceof AST.NameExpr symbolExpr) { Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; code(new Instruction.Store(varSymbol.reg.slot)); @@ -122,7 +130,7 @@ else if (assignStmt.lhs instanceof AST.NameExpr symbolExpr) { private void compileExprStmt(AST.ExprStmt exprStmt) { boolean indexed = compileExpr(exprStmt.expr); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); code(new Instruction.Pop()); } @@ -149,7 +157,7 @@ private void compileWhile(AST.WhileStmt whileStmt) { startBlock(loopBlock); boolean indexed = compileExpr(whileStmt.condition); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); code(new Instruction.ConditionalBranch(currentBlock, bodyBlock, exitBlock)); startBlock(bodyBlock); compileStatement(whileStmt.stmt); @@ -184,7 +192,7 @@ private void compileIf(AST.IfElseStmt ifElseStmt) { BasicBlock exitBlock = createBlock(); boolean indexed = compileExpr(ifElseStmt.condition); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); code(new Instruction.ConditionalBranch(currentBlock, ifBlock, needElse ? elseBlock : exitBlock)); startBlock(ifBlock); compileStatement(ifElseStmt.ifStmt); @@ -203,7 +211,7 @@ private void compileLet(AST.VarStmt letStmt) { if (letStmt.expr != null) { boolean indexed = compileExpr(letStmt.expr); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); code(new Instruction.Store(letStmt.symbol.reg.slot)); } } @@ -246,7 +254,7 @@ private boolean compileCallExpr(AST.CallExpr callExpr) { for (AST.Expr expr: callExpr.args) { boolean indexed = compileExpr(expr); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); } code(new Instruction.Call(callExpr.args.size())); return false; @@ -271,7 +279,7 @@ private boolean compileFieldExpr(AST.FieldExpr fieldExpr) { throw new CompilerException("Field " + fieldExpr.fieldName + " not found"); boolean indexed = compileExpr(fieldExpr.object); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); code(new Instruction.PushConst(fieldIndex)); return true; } @@ -280,7 +288,7 @@ private boolean compileArrayIndexExpr(AST.ArrayIndexExpr arrayIndexExpr) { compileExpr(arrayIndexExpr.array); boolean indexed = compileExpr(arrayIndexExpr.expr); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); return true; } @@ -292,8 +300,8 @@ private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { code(new Instruction.PushConst(fieldIndex)); boolean indexed = compileExpr(setFieldExpr.value); if (indexed) - code(new Instruction.LoadIndexed()); - code(new Instruction.StoreIndexed()); + codeIndexedLoad(); + codeIndexedStore(); return false; } @@ -305,7 +313,7 @@ private boolean compileNewExpr(AST.NewExpr newExpr) { // Maybe have specific AST similar to how we have SetFieldExpr? boolean indexed = compileExpr(expr); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); code(new Instruction.StoreAppend()); } } @@ -332,10 +340,10 @@ private boolean compileBinaryExpr(AST.BinaryExpr binaryExpr) { int opCode = 0; boolean indexed = compileExpr(binaryExpr.expr1); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); indexed = compileExpr(binaryExpr.expr2); if (indexed) - code(new Instruction.LoadIndexed()); + codeIndexedLoad(); switch (binaryExpr.op.str) { case "+" -> opCode = Instruction.ADD_I; case "-" -> opCode = Instruction.SUB_I; @@ -373,4 +381,11 @@ private boolean compileConstantExpr(AST.LiteralExpr constantExpr) { return false; } + private void codeIndexedLoad() { + code(new Instruction.LoadIndexed()); + } + + private void codeIndexedStore() { + code(new Instruction.StoreIndexed()); + } } diff --git a/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java new file mode 100644 index 0000000..5c0b365 --- /dev/null +++ b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -0,0 +1,44 @@ +package com.compilerprogramming.ezlang.compiler; + +import com.compilerprogramming.ezlang.lexer.Lexer; +import com.compilerprogramming.ezlang.parser.Parser; +import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; +import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; +import com.compilerprogramming.ezlang.types.Symbol; +import com.compilerprogramming.ezlang.types.Type; +import com.compilerprogramming.ezlang.types.TypeDictionary; + +import java.util.BitSet; + +public class Compiler { + + private void compile(TypeDictionary typeDictionary) { + for (Symbol symbol: typeDictionary.getLocalSymbols()) { + if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { + Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; + functionType.code = new CompiledFunction(functionSymbol); + } + } + } + public TypeDictionary compileSrc(String src) { + Parser parser = new Parser(); + var program = parser.parse(new Lexer(src)); + var typeDict = new TypeDictionary(); + var sema = new SemaDefineTypes(typeDict); + sema.analyze(program); + var sema2 = new SemaAssignTypes(typeDict); + sema2.analyze(program); + compile(typeDict); + return typeDict; + } + public String dumpIR(TypeDictionary typeDictionary) { + StringBuilder sb = new StringBuilder(); + for (Symbol s: typeDictionary.bindings.values()) { + if (s instanceof Symbol.FunctionTypeSymbol f) { + var functionBuilder = (CompiledFunction) f.code(); + BasicBlock.toStr(sb, functionBuilder.entry, new BitSet()); + } + } + return sb.toString(); + } +} diff --git a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java similarity index 99% rename from stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java rename to stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java index 14904bf..bc195ef 100644 --- a/stackvm/src/main/java/com/compilerprogramming/ezlang/bytecode/Instruction.java +++ b/stackvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java @@ -1,4 +1,4 @@ -package com.compilerprogramming.ezlang.bytecode; +package com.compilerprogramming.ezlang.compiler; import com.compilerprogramming.ezlang.types.Type; diff --git a/stackvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java b/stackvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java deleted file mode 100644 index 5a5fd9c..0000000 --- a/stackvm/src/test/java/com/compilerprogramming/ezlang/bytecode/TestCompiler.java +++ /dev/null @@ -1,290 +0,0 @@ -package com.compilerprogramming.ezlang.bytecode; - -import com.compilerprogramming.ezlang.lexer.Lexer; -import com.compilerprogramming.ezlang.parser.Parser; -import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; -import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; -import com.compilerprogramming.ezlang.types.Symbol; -import com.compilerprogramming.ezlang.types.TypeDictionary; -import org.junit.Test; - -import java.util.BitSet; - -public class TestCompiler { - - void compileSrc(String src, String functionName) { - Parser parser = new Parser(); - var program = parser.parse(new Lexer(src)); - var typeDict = new TypeDictionary(); - var sema = new SemaDefineTypes(typeDict); - sema.analyze(program); - var sema2 = new SemaAssignTypes(typeDict); - sema2.analyze(program); - ByteCodeCompiler byteCodeCompiler = new ByteCodeCompiler(); - byteCodeCompiler.compile(typeDict); - for (Symbol s: typeDict.bindings.values()) { - if (s instanceof Symbol.FunctionTypeSymbol f) { - var functionBuilder = (BytecodeFunction) f.code(); - System.out.println(BasicBlock.toStr(new StringBuilder(), functionBuilder.entry, new BitSet())); - } - } - } - - @Test - public void testFunction1() { - String src = """ - func foo(n: Int)->Int { - return 1; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction2() { - String src = """ - func foo(n: Int)->Int { - return -1; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction3() { - String src = """ - func foo(n: Int)->Int { - return n; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction4() { - String src = """ - func foo(n: Int)->Int { - return -n; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction5() { - String src = """ - func foo(n: Int)->Int { - return n+1; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction6() { - String src = """ - func foo(n: Int)->Int { - return 1+1; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction7() { - String src = """ - func foo(n: Int)->Int { - return 1+1-1; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction8() { - String src = """ - func foo(n: Int)->Int { - return 2==2; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction9() { - String src = """ - func foo(n: Int)->Int { - return 1!=1; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction10() { - String src = """ - func foo(n: [Int])->Int { - return n[0]; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction11() { - String src = """ - func foo(n: [Int])->Int { - return n[0]+n[1]; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction12() { - String src = """ - func foo()->[Int] { - return new [Int] { 1, 2, 3 }; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction13() { - String src = """ - func foo(n: Int) -> [Int] { - return new [Int] { n }; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction14() { - String src = """ - func add(x: Int, y: Int) -> Int { - return x+y; - } - """; - compileSrc(src, "add"); - } - - @Test - public void testFunction14a() { - String src = """ - struct Person - { - var age: Int - var children: Int - } - func foo(p: Person) -> Person { - p.age = 10; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction14b() { - String src = """ - struct Person - { - var age: Int - var children: Int - } - func foo() -> Person { - return new Person { age=10, children=0 }; - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction14c() { - String src = """ - func foo(array: [Int]) { - array[0] = 1 - array[1] = 2 - } - """; - compileSrc(src, "foo"); - } - - @Test - public void testFunction15() { - String src = """ - func min(x: Int, y: Int) -> Int { - if (x < y) - return x; - return y; - } - """; - compileSrc(src, "min"); - } - - @Test - public void testFunction16() { - String src = """ - func loop() { - while (1) - return; - return; - } - """; - compileSrc(src, "loop"); - } - - @Test - public void testFunction17() { - String src = """ - func loop() { - while (1) - break; - return; - } - """; - compileSrc(src, "loop"); - } - - @Test - public void testFunction18() { - String src = """ - func loop(n: Int) { - while (n > 0) { - n = n - 1; - } - return; - } - """; - compileSrc(src, "loop"); - } - - @Test - public void testFunction19() { - String src = """ - func foo() {} - func bar() { foo(); } - """; - compileSrc(src, "bar"); - } - - @Test - public void testFunction20() { - String src = """ - func foo(x: Int, y: Int) {} - func bar() { foo(1,2); } - """; - compileSrc(src, "bar"); - } - - @Test - public void testFunction21() { - String src = """ - func foo(x: Int, y: Int)->Int { return x+y; } - func bar()->Int { var t = foo(1,2); return t+1; } - """; - compileSrc(src, "bar"); - } - -} diff --git a/stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java b/stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java new file mode 100644 index 0000000..eeb0a02 --- /dev/null +++ b/stackvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestCompiler.java @@ -0,0 +1,630 @@ +package com.compilerprogramming.ezlang.compiler; + +import com.compilerprogramming.ezlang.lexer.Lexer; +import com.compilerprogramming.ezlang.parser.Parser; +import com.compilerprogramming.ezlang.semantic.SemaAssignTypes; +import com.compilerprogramming.ezlang.semantic.SemaDefineTypes; +import com.compilerprogramming.ezlang.types.Symbol; +import com.compilerprogramming.ezlang.types.TypeDictionary; +import org.junit.Assert; +import org.junit.Test; + +import java.util.BitSet; + +public class TestCompiler { + + String compileSrc(String src) { + var compiler = new Compiler(); + var typeDict = compiler.compileSrc(src); + return compiler.dumpIR(typeDict); + } + + @Test + public void testFunction1() { + String src = """ + func foo(n: Int)->Int { + return 1; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + pushi 1 + jump L1 +L1: +""", result); + } + + @Test + public void testFunction2() { + String src = """ + func foo(n: Int)->Int { + return -1; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + pushi 1 + negi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction3() { + String src = """ + func foo(n: Int)->Int { + return n; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + jump L1 +L1: +""", result); + } + + @Test + public void testFunction4() { + String src = """ + func foo(n: Int)->Int { + return -n; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + negi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction5() { + String src = """ + func foo(n: Int)->Int { + return n+1; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + pushi 1 + addi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction6() { + String src = """ + func foo(n: Int)->Int { + return 1+1; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + pushi 1 + pushi 1 + addi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction7() { + String src = """ + func foo(n: Int)->Int { + return 1+1-1; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + pushi 1 + pushi 1 + addi + pushi 1 + subi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction8() { + String src = """ + func foo(n: Int)->Int { + return 2==2; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + pushi 2 + pushi 2 + eq + jump L1 +L1: +""", result); + } + + @Test + public void testFunction9() { + String src = """ + func foo(n: Int)->Int { + return 1!=1; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + pushi 1 + pushi 1 + neq + jump L1 +L1: +""", result); + } + + @Test + public void testFunction10() { + String src = """ + func foo(n: [Int])->Int { + return n[0]; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + pushi 0 + loadindexed + jump L1 +L1: +""", result); + } + + @Test + public void testFunction11() { + String src = """ + func foo(n: [Int])->Int { + return n[0]+n[1]; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + pushi 0 + loadindexed + load 0 + pushi 1 + loadindexed + addi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction12() { + String src = """ + func foo()->[Int] { + return new [Int] { 1, 2, 3 }; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + new [Int,Int] + pushi 1 + storeappend + pushi 2 + storeappend + pushi 3 + storeappend + jump L1 +L1: +""", result); + } + + @Test + public void testFunction13() { + String src = """ + func foo(n: Int) -> [Int] { + return new [Int] { n }; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + new [Int,Int] + load 0 + storeappend + jump L1 +L1: +""", result); + } + + @Test + public void testFunction14() { + String src = """ + func add(x: Int, y: Int) -> Int { + return x+y; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + load 1 + addi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction15() { + String src = """ + struct Person + { + var age: Int + var children: Int + } + func foo(p: Person) -> Person { + p.age = 10; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + pushi 0 + pushi 10 + storeindexed + jump L1 +L1: +""", result); + } + + @Test + public void testFunction16() { + String src = """ + struct Person + { + var age: Int + var children: Int + } + func foo() -> Person { + return new Person { age=10, children=0 }; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + new Person + pushi 0 + pushi 10 + storeindexed + pushi 1 + pushi 0 + storeindexed + jump L1 +L1: +""", result); + } + + @Test + public void testFunction17() { + String src = """ + func foo(array: [Int]) { + array[0] = 1 + array[1] = 2 + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + pushi 0 + pushi 1 + storeindexed + load 0 + pushi 1 + pushi 2 + storeindexed + jump L1 +L1: +""", result); + } + + @Test + public void testFunction18() { + String src = """ + func min(x: Int, y: Int) -> Int { + if (x < y) + return x; + return y; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + load 1 + lt + cbr L2 L3 +L2: + load 0 + jump L1 +L1: +L3: + load 1 + jump L1 +""", result); + } + + @Test + public void testFunction19() { + String src = """ + func loop() { + while (1) + return; + return; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + jump L2 +L2: + pushi 1 + cbr L3 L4 +L3: + jump L1 +L1: +L4: + jump L1 +""", result); + } + + @Test + public void testFunction20() { + String src = """ + func loop() { + while (1) + break; + return; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + jump L2 +L2: + pushi 1 + cbr L3 L4 +L3: + jump L4 +L4: + jump L1 +L1: +""", result); + } + + @Test + public void testFunction21() { + String src = """ + func loop(n: Int) { + while (n > 0) { + n = n - 1; + } + return; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + jump L2 +L2: + load 0 + pushi 0 + gt + cbr L3 L4 +L3: + load 0 + pushi 1 + subi + store 0 + jump L2 +L4: + jump L1 +L1: +""", result); + } + + @Test + public void testFunction22() { + String src = """ + func foo() {} + func bar() { foo(); } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + jump L1 +L1: +L0: + loadfunc foo + call 0 + pop + jump L1 +L1: +""", result); + } + + @Test + public void testFunction23() { + String src = """ + func foo(x: Int, y: Int) {} + func bar() { foo(1,2); } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + jump L1 +L1: +L0: + loadfunc foo + pushi 1 + pushi 2 + call 2 + pop + jump L1 +L1: +""", result); + } + + @Test + public void testFunction24() { + String src = """ + func foo(x: Int, y: Int)->Int { return x+y; } + func bar()->Int { var t = foo(1,2); return t+1; } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + load 1 + addi + jump L1 +L1: +L0: + loadfunc foo + pushi 1 + pushi 2 + call 2 + store 0 + load 0 + pushi 1 + addi + jump L1 +L1: +""", result); + } + + @Test + public void testFunction25() { + String src = """ + struct Person + { + var age: Int + var children: Int + } + func foo(p: Person) -> Int { + return p.age; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + pushi 0 + loadindexed + jump L1 +L1: +""", result); + } + + @Test + public void testFunction26() { + String src = """ + struct Person + { + var age: Int + var parent: Person + } + func foo(p: Person) -> Int { + return p.parent.age; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + pushi 1 + loadindexed + pushi 0 + loadindexed + jump L1 +L1: +""", result); + } + + @Test + public void testFunction27() { + String src = """ + struct Person + { + var age: Int + var parent: Person + } + func foo(p: [Person], i: Int) -> Int { + return p[i].parent.age; + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + load 1 + loadindexed + pushi 1 + loadindexed + pushi 0 + loadindexed + jump L1 +L1: +""", result); + } + + @Test + public void testFunction28() { + String src = """ + func foo(x: Int, y: Int)->Int { return x+y; } + func bar(a: Int)->Int { var t = foo(a,2); return t+1; } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +L0: + load 0 + load 1 + addi + jump L1 +L1: +L0: + loadfunc foo + load 0 + pushi 2 + call 2 + store 1 + load 1 + pushi 1 + addi + jump L1 +L1: +""", result); + } +}