From cfb505524204b7052f0e4ee1cf20460d271264e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:37:03 +0800 Subject: [PATCH 01/54] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a5eb2256..b810622e 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,8 @@ Coderive replaces traditional boolean operators with expressive quantifiers: ```python share Calculator { - ~| int result, string operation # Return slot declarations - local calculate(int a, int b) { + local calculate(int a, int b) :: result: int, operation: text /* Return slot declarations */ + { ~> a + b, "addition" # Slot assignments } } @@ -104,7 +104,7 @@ for i by *2 in 1 to 10 { # Complex step patterns unit sample.program get { - cod.Math + lang.Math } share InteractiveDemo { From 66222124c155c28f9b57e1ae9955f073e56d355a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:40:56 +0800 Subject: [PATCH 02/54] Update README.md --- README.md | 53 +++++++---------------------------------------------- 1 file changed, 7 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index b810622e..c6516aae 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,8 @@ Coderive replaces traditional boolean operators with expressive quantifiers: ```python share Calculator { - local calculate(int a, int b) :: result: int, operation: text /* Return slot declarations */ + local calculate(int a, int b) + :: result: int, operation: text { ~> a + b, "addition" # Slot assignments } @@ -110,7 +111,7 @@ get { share InteractiveDemo { ~| int formula, string operation - local calculate(int a, int b, string op) { + local calculate(a: int, b: int, op: text) { if all[a >= 0, b >= 0] { if op == any["+", "-", "*"] { ~> a + b, "valid operation" @@ -121,21 +122,10 @@ share InteractiveDemo { } ``` -## 4. Performance Validation +## 4. Compiler -The system demonstrates efficient execution across both interpreter and native compilation targets. -Internal performance profiling shows that Coderive's quantifier operations approach the efficiency of -highly optimized data structures in established languages. - -
- -|Feature|Status|Target|Details| -|-------|------|------|-------| -|Interpreter|✅ Working|JVM Bytecode|Full language support| -|Native Compilation|✅ Working|ARM64/x86_64|Advanced register allocation| -|Quantifier Performance|✅ Validated|All targets|Efficient short-circuiting| - -
+The system has an on going TAC Compiler for efficient execution across both interpreter and native compilation targets. +Internal performance profiling shows that ## 5. Getting Started @@ -155,33 +145,6 @@ java -jar coderive.jar program.cod java -jar coderive.jar --native program.cod ``` -**Compilation Output** - -``` -[20:26:28.018] [INFO] RUNNER: Starting MTOT compilation pipeline -[20:26:28.056] [INFO] RUNNER: AST built successfully -[20:26:28.068] [INFO] BYTECODE: Compilation complete: 1076 instructions across 9 methods -[20:26:28.227] [INFO] MTOT: Full compilation pipeline complete. -``` - -**Generated Assembly Sample** - -A snippet of the resulting ARM64 assembly code from the compilation pipeline: - -```assembly - .text - .global add -add: - stp x29, x30, [sp, #-16]! - mov x29, sp - sub sp, sp, #48 - // Saving callee-saved registers - stp x19, x20, [x29, #-16] - // ... ARM64 assembly code - mov x0, x23 - ret -``` - ## 6. Current Status
@@ -190,9 +153,7 @@ add: |---------|------|-----| |Interpreter|✅ Complete|Full language features| |Native Code Generation|✅ Complete|ARM64/x86_64 support| -|Register Allocation|✅ Complete|Predictive spilling| -|String Handling|🔧 In Progress|Enhanced implementation| -|Type System|🔧 In Progress|Extended features| +|TAC Compiler|🔧 In Progress|Enhanced implementation|
From 220b5aceb905ce36cb2fc675474c3914939017ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:42:22 +0800 Subject: [PATCH 03/54] Fix syntax in InteractiveDemo section of README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c6516aae..5752a47b 100644 --- a/README.md +++ b/README.md @@ -110,8 +110,9 @@ get { share InteractiveDemo { - ~| int formula, string operation - local calculate(a: int, b: int, op: text) { + local calculate(a: int, b: int, op: text) + :: formula: int, operation: text + { if all[a >= 0, b >= 0] { if op == any["+", "-", "*"] { ~> a + b, "valid operation" From 96bbeacfd59afb4b9d29f8d19b4d07e6084f79a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:54:35 +0800 Subject: [PATCH 04/54] Delete src/main/java/cod/Constants.java --- src/main/java/cod/Constants.java | 96 -------------------------------- 1 file changed, 96 deletions(-) delete mode 100644 src/main/java/cod/Constants.java diff --git a/src/main/java/cod/Constants.java b/src/main/java/cod/Constants.java deleted file mode 100644 index 11be8af6..00000000 --- a/src/main/java/cod/Constants.java +++ /dev/null @@ -1,96 +0,0 @@ -package cod; - -public class Constants { - - public static final String - share = "share", - local = "local", - unit = "unit", - get = "get", - extend = "extend", - this_ = "this", - var = "var", - input_ = "input", - output = "output", - if_ = "if", - else_ = "else", - elif_ = "elif", - for_ = "for", - in_ = "in", - to_ = "to", - by_ = "by", - int_ = "int", - string = "string", - float_ = "float", - bool = "bool", - true_ = "true", - false_ = "false", - builtin = "builtin", - all = "all", - any = "any" - ; - - public static final String - _share = "share", - _local = "LOCAL", - _unit = "UNIT", - _get = "GET", - _extend = "EXTEND", - _this = "THIS", - _var = "VAR", - _output = "OUTPUT", - _input = "INPUT", - _if = "IF", - _else = "ELSE", - _elif = "ELIF", - _for = "FOR", - _in = "IN", - _to = "TO", - _by = "BY", - _int = "INT", - _string = "STRING", - _float = "FLOAT", - _bool = "BOOL", - _eof = "EOF", - _int_lit = "INT_LIT", - _float_lit = "FLOAT_LIT", - _string_lit = "STRING_LIT", - _bool_lit = "BOOL_LIT", - _id = "ID", - _assign = "ASSIGN", - _plus = "PLUS", - _minus = "MINUS", - _mul = "MUL", - _div = "DIV", - _mod = "MOD", - _colon = "COLON", - _gt = "GT", - _lt = "LT", - _gte = "GTE", - _lte = "LTE", - _eq = "EQ", - _neq = "NEQ", - _dot = "DOT", - _comma = "COMMA", - _lparen = "LPAREN", - _rparen = "RPAREN", - _lbrace = "LBRACE", - _rbrace = "RBRACE", - _lbracket = "LBRACKET", - _rbracket = "RBRACKET", - _plus_assign = "PLUS_ASSIGN", - _minus_assign = "MINUS_ASSIGN", - _mul_assign = "MUL_ASSIGN", - _div_assign = "DIV_ASSIGN", - _builtin = "BUILTIN", - _all = "ALL", - _any = "ANY", - _bang = "BANG", - _tilde_bar = "TILDE_BAR", - _tilde_arrow = "TILDE_ARROW", - _line_comment = "LINE_COMMENT", - _block_comment = "BLOCK_COMMENT", - _ws = "WS", - _invalid = "INVALID" - ; -} \ No newline at end of file From 741b68b11f2039c949ffe40f6de8a9a7b3ec98af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:55:08 +0800 Subject: [PATCH 05/54] Delete src/main/java/cod/runner/CompilationEngine.java --- .../java/cod/runner/CompilationEngine.java | 94 ------------------- 1 file changed, 94 deletions(-) delete mode 100644 src/main/java/cod/runner/CompilationEngine.java diff --git a/src/main/java/cod/runner/CompilationEngine.java b/src/main/java/cod/runner/CompilationEngine.java deleted file mode 100644 index 07c09744..00000000 --- a/src/main/java/cod/runner/CompilationEngine.java +++ /dev/null @@ -1,94 +0,0 @@ -package cod.runner; - -import cod.ast.nodes.ProgramNode; -import cod.compiler.BytecodeCompiler; -import cod.compiler.BytecodeProgram; -import cod.compiler.BytecodeInstruction; -import cod.compiler.MTOTNativeCompiler; -import cod.compiler.MTOTRegistry; -import cod.debug.DebugSystem; - -import java.io.*; -import java.util.List; -import java.util.Map; - -public class CompilationEngine { - private static final String LOG_TAG = "COMPILATION_ENGINE"; - - private final BytecodeCompiler bytecodeCompiler; - private MTOTNativeCompiler nativeCompiler; - - public CompilationEngine() { - this.bytecodeCompiler = new BytecodeCompiler(); - } - - public BytecodeProgram compileToBytecode(ProgramNode ast, boolean disassemble) { - DebugSystem.info(LOG_TAG, "Starting bytecode compilation"); - DebugSystem.startTimer("bytecode_compilation"); - - BytecodeProgram bytecode = bytecodeCompiler.compile(ast); - - if (disassemble) { - bytecode.disassemble(); - } - - DebugSystem.stopTimer("bytecode_compilation"); - DebugSystem.info(LOG_TAG, "Bytecode compilation completed"); - return bytecode; - } - - public void compileToNative(BytecodeProgram bytecode, String outputFilename) { - DebugSystem.info(LOG_TAG, "Starting native compilation"); - DebugSystem.startTimer("native_compilation"); - - if (nativeCompiler == null) { - MTOTRegistry.CPUProfile cpu = MTOTRegistry.detectCPU(); - DebugSystem.info("MTOT", "Detected CPU: " + cpu.architecture); - nativeCompiler = new MTOTNativeCompiler(cpu); - } - - for (Map.Entry> entry : bytecode.getMethods().entrySet()) { - String methodName = entry.getKey(); - List methodBytecode = entry.getValue(); - String assembly = nativeCompiler.compileMethodFromBytecode(methodName, methodBytecode); - bytecode.addNativeMethod(methodName, assembly); - } - - DebugSystem.stopTimer("native_compilation"); - - if (outputFilename != null) { - writeNativeAssembly(bytecode, outputFilename); - } else { - printNativeAssembly(bytecode); - } - - DebugSystem.info(LOG_TAG, "Native compilation completed"); - } - - public void compileFullPipeline(ProgramNode ast, String outputFilename, boolean disassemble) { - BytecodeProgram bytecode = compileToBytecode(ast, disassemble); - compileToNative(bytecode, outputFilename); - } - - private void writeNativeAssembly(BytecodeProgram bytecode, String outputFilename) { - DebugSystem.info(LOG_TAG, "Writing native assembly to " + outputFilename); - try { - PrintWriter out = new PrintWriter(new FileOutputStream(outputFilename)); - try { - for (Map.Entry entry : bytecode.getNativeMethods().entrySet()) { - out.println(entry.getValue()); - } - } finally { - out.close(); - } - } catch (IOException e) { - throw new RuntimeException("Failed to write output file: " + e.getMessage(), e); - } - } - - private void printNativeAssembly(BytecodeProgram bytecode) { - for (Map.Entry entry : bytecode.getNativeMethods().entrySet()) { - System.out.println(entry.getValue()); - } - } -} \ No newline at end of file From a52436f9c9b8e610598d148473c06c46f04b85ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:55:51 +0800 Subject: [PATCH 06/54] Delete src/main/java/cod/compiler/natives directory --- .../compiler/natives/ControlFlowCompiler.java | 63 ---- .../natives/MemoryAccessCompiler.java | 253 --------------- .../compiler/natives/MethodCallCompiler.java | 306 ------------------ .../cod/compiler/natives/OperandStack.java | 60 ---- .../compiler/natives/OperationCompiler.java | 82 ----- .../compiler/natives/RuntimeCallHelper.java | 121 ------- 6 files changed, 885 deletions(-) delete mode 100644 src/main/java/cod/compiler/natives/ControlFlowCompiler.java delete mode 100644 src/main/java/cod/compiler/natives/MemoryAccessCompiler.java delete mode 100644 src/main/java/cod/compiler/natives/MethodCallCompiler.java delete mode 100644 src/main/java/cod/compiler/natives/OperandStack.java delete mode 100644 src/main/java/cod/compiler/natives/OperationCompiler.java delete mode 100644 src/main/java/cod/compiler/natives/RuntimeCallHelper.java diff --git a/src/main/java/cod/compiler/natives/ControlFlowCompiler.java b/src/main/java/cod/compiler/natives/ControlFlowCompiler.java deleted file mode 100644 index 6a6b5975..00000000 --- a/src/main/java/cod/compiler/natives/ControlFlowCompiler.java +++ /dev/null @@ -1,63 +0,0 @@ -package cod.compiler.natives; - -import cod.compiler.MTOTNativeCompiler; -import cod.compiler.RegisterManager; - -public class ControlFlowCompiler { - private final MTOTNativeCompiler compiler; - private final cod.compiler.natives.OperandStack operandStack; - private final RegisterManager.RegisterAllocator registerAllocator; - private final RegisterManager.RegisterSpiller spiller; - - public ControlFlowCompiler(MTOTNativeCompiler compiler) { - this.compiler = compiler; - this.operandStack = compiler.operandStack; - this.registerAllocator = compiler.registerManager.getAllocator(); - this.spiller = compiler.registerManager.getSpiller(); - } - - public void compileJmp(String label) { - if (label == null) { - cod.debug.DebugSystem.error("MTOT", "JMP target label is null!"); - return; - } - compiler.assemblyCode.add(" " + compiler.cpuProfile.getPattern("jmp").assemblyTemplate.get(0).replace("{label}", label)); - } - - public void compileJmpIfFalse(String label) { - if (label == null) { - cod.debug.DebugSystem.error("MTOT", "JMP_IF_FALSE target label is null!"); - return; - } - String c = operandStack.popToRegister(); - spiller.fillRegister(c); - for (String t : compiler.cpuProfile.getPattern("jmp_if_false").assemblyTemplate) { - compiler.assemblyCode.add(" " + t.replace("{condition}", c).replace("{label}", label)); - } - registerAllocator.freeRegister(c); - } - - public void compileJmpIfTrue(String label) { - if (label == null) { - cod.debug.DebugSystem.error("MTOT", "JMP_IF_TRUE target label is null!"); - return; - } - String c = operandStack.popToRegister(); - spiller.fillRegister(c); - cod.compiler.MTOTRegistry.InstructionPattern p = compiler.cpuProfile.getPattern("jmp_if_true"); - if (p == null) { - if (compiler.cpuProfile.architecture.equals("aarch64")) { - compiler.assemblyCode.add(" cmp " + c + ", #0"); - compiler.assemblyCode.add(" b.ne " + label); - } else { - compiler.assemblyCode.add(" test " + c + ", " + c); - compiler.assemblyCode.add(" jnz " + label); - } - } else { - for (String t : p.assemblyTemplate) { - compiler.assemblyCode.add(" " + t.replace("{condition}", c).replace("{label}", label)); - } - } - registerAllocator.freeRegister(c); - } -} \ No newline at end of file diff --git a/src/main/java/cod/compiler/natives/MemoryAccessCompiler.java b/src/main/java/cod/compiler/natives/MemoryAccessCompiler.java deleted file mode 100644 index 33d283e7..00000000 --- a/src/main/java/cod/compiler/natives/MemoryAccessCompiler.java +++ /dev/null @@ -1,253 +0,0 @@ -package cod.compiler.natives; - -import cod.compiler.MTOTNativeCompiler; -import cod.compiler.RegisterManager; - -import cod.debug.DebugSystem; - -import java.util.*; - -public class MemoryAccessCompiler { - private final MTOTNativeCompiler compiler; - private final cod.compiler.natives.OperandStack operandStack; - private final RegisterManager.RegisterAllocator registerAllocator; - private final RegisterManager.RegisterSpiller spiller; - - private Map fieldOffsets = new HashMap(); - private int nextFieldOffset = 0; - private Map slotLocations = new HashMap(); - private Map stringLiteralLabels = new HashMap(); - - public MemoryAccessCompiler(MTOTNativeCompiler compiler) { - this.compiler = compiler; - this.operandStack = compiler.operandStack; - this.registerAllocator = compiler.registerManager.getAllocator(); - this.spiller = compiler.registerManager.getSpiller(); - } - - public void reset() { - fieldOffsets.clear(); - nextFieldOffset = 0; - slotLocations.clear(); - stringLiteralLabels.clear(); - } - - public Map getSlotLocations() { - return new HashMap(slotLocations); - } - - private int getFieldOffset(String fieldName) { - if (!fieldOffsets.containsKey(fieldName)) { - fieldOffsets.put(fieldName, nextFieldOffset); - cod.debug.DebugSystem.debug("MTOT_FIELDS", "Assigned offset " + nextFieldOffset + " to field '" + fieldName + "'"); - nextFieldOffset += 8; - } - return fieldOffsets.get(fieldName).intValue(); - } - - public void compilePushInt(int value) { - String r = registerAllocator.allocateRegister(); - cod.compiler.MTOTRegistry.InstructionPattern p = compiler.cpuProfile.getPattern("load_immediate_int"); - compiler.assemblyCode.add(" " + p.assemblyTemplate.get(0).replace("{dest}", r).replace("{value}", String.valueOf(value))); - operandStack.pushFromRegister(r); - spiller.markRegisterModified(r); - } - - public void compilePushFloat(float value) { - // Create float constant in data section - String label = compiler.generateDataLabel("float"); - String directive = compiler.cpuProfile.syntax.floatDirective - .replace("{label}", label) - .replace("{value}", String.valueOf(value)); - compiler.dataSection.add(directive); - - // Allocate register for the float value - String r = registerAllocator.allocateRegister(); - - // Load the actual float value from memory - if (compiler.cpuProfile.architecture.equals("x86_64")) { - // x86_64: Use SSE registers for floats (simplified - load into general purpose register) - // For proper float handling, we'd need XMM registers, but for now load as integer - compiler.assemblyCode.add(" mov " + r + ", [" + label + "] " + compiler.cpuProfile.syntax.commentMarker + " Load float value (as integer)"); - } else { - // AArch64: Load float value - compiler.assemblyCode.add(" ldr " + r + ", [" + label + "] " + compiler.cpuProfile.syntax.commentMarker + " Load float value"); - } - - operandStack.pushFromRegister(r); - spiller.markRegisterModified(r); - - DebugSystem.debug("MTOT_FLOAT", "Pushed float value " + value + " (label: " + label + ")"); -} - - public void compilePushString(String str) { - String label; - if (stringLiteralLabels.containsKey(str)) { - label = stringLiteralLabels.get(str); - cod.debug.DebugSystem.debug("MTOT_STR", "Reusing string literal label '" + label + "' for: \"" + compiler.escapeString(str) + "\""); - } else { - label = compiler.generateDataLabel("str"); - String directive = compiler.cpuProfile.syntax.stringDirective.replace("{label}", label).replace("{value}", compiler.escapeString(str)); - compiler.dataSection.add(directive); - stringLiteralLabels.put(str, label); - cod.debug.DebugSystem.debug("MTOT_STR", "Created string literal label '" + label + "' for: \"" + compiler.escapeString(str) + "\""); - } - String r = registerAllocator.allocateRegister(); - for(String t : compiler.cpuProfile.getPattern("load_address").assemblyTemplate) { - compiler.assemblyCode.add(" "+t.replace("{dest}",r).replace("{label}",label)); - } - operandStack.pushFromRegister(r); - spiller.markRegisterModified(r); - } - - public void compilePushNull() { - String r = registerAllocator.allocateRegister(); - cod.compiler.MTOTRegistry.InstructionPattern p = compiler.cpuProfile.getPattern("load_immediate_int"); - compiler.assemblyCode.add(" " + p.assemblyTemplate.get(0).replace("{dest}", r).replace("{value}", "0")); - operandStack.pushFromRegister(r); - spiller.markRegisterModified(r); - } - - public void compilePop() { - if (!operandStack.isEmpty()) { - String r = operandStack.popToRegister(); - registerAllocator.freeRegister(r); - cod.debug.DebugSystem.debug("MTOT_REG", "POP freed register: " + r); - } else { - cod.debug.DebugSystem.warn("MTOT", "POP on empty stack."); - } - } - - public void compileDup() { - String r = operandStack.peek(); - if (r != null) { - spiller.fillRegister(r); - String n = registerAllocator.allocateRegister(Collections.singleton(r)); - compiler.assemblyCode.add(" " + compiler.cpuProfile.getPattern("move_reg").assemblyTemplate.get(0).replace("{dest}", n).replace("{src}", r)); - operandStack.pushFromRegister(n); - spiller.markRegisterModified(n); - } else { - throw new RuntimeException("DUP on empty stack."); - } - } - - public void compileSwap() { - String r1 = operandStack.popToRegister(); - String r2 = operandStack.popToRegister(); - operandStack.pushFromRegister(r1); - operandStack.pushFromRegister(r2); - cod.debug.DebugSystem.debug("MTOT_REG", "SWAPped " + r1 + " and " + r2 + " on stack"); - } - - public void compileLoadField(String fieldName) { - int offset = getFieldOffset(fieldName); - String destReg = registerAllocator.allocateRegister(Collections.singleton(compiler.thisRegister)); - spiller.fillRegister(compiler.thisRegister); - cod.compiler.MTOTRegistry.InstructionPattern pattern = compiler.cpuProfile.getPattern("load_field_offset"); - if (pattern == null) throw new RuntimeException("Missing 'load_field_offset' pattern!"); - String asm = pattern.assemblyTemplate.get(0) - .replace("{dest_reg}", destReg) - .replace("{base_reg}", compiler.thisRegister) - .replace("{offset}", String.valueOf(offset)); - compiler.assemblyCode.add(" " + compiler.cpuProfile.syntax.commentMarker + " Load field " + fieldName + " (offset " + offset + ")"); - compiler.assemblyCode.add(" " + asm); - operandStack.pushFromRegister(destReg); - spiller.markRegisterModified(destReg); - } - - public void compileStoreField(String fieldName) { - int offset = getFieldOffset(fieldName); - String valueReg = operandStack.popToRegister(); - spiller.fillRegister(compiler.thisRegister); - spiller.fillRegister(valueReg); - cod.compiler.MTOTRegistry.InstructionPattern pattern = compiler.cpuProfile.getPattern("store_field_offset"); - if (pattern == null) throw new RuntimeException("Missing 'store_field_offset' pattern!"); - String asm = pattern.assemblyTemplate.get(0) - .replace("{src_reg}", valueReg) - .replace("{base_reg}", compiler.thisRegister) - .replace("{offset}", String.valueOf(offset)); - compiler.assemblyCode.add(" " + compiler.cpuProfile.syntax.commentMarker + " Store field " + fieldName + " (offset " + offset + ")"); - compiler.assemblyCode.add(" " + asm); - registerAllocator.freeRegister(valueReg); - } - - public void compileStoreLocal(int slotIndex, Map localRegisterMap) { - String valueReg = operandStack.popToRegister(); - String varRegKey = "local_" + slotIndex; - String targetReg = localRegisterMap.get(varRegKey); - - if (targetReg == null) { - targetReg = registerAllocator.allocateRegister(Collections.singleton(valueReg)); - localRegisterMap.put(varRegKey, targetReg); - spiller.mapSlotToRegister(slotIndex, targetReg); - cod.debug.DebugSystem.debug("MTOT_REG", "Allocated register " + targetReg + " for " + varRegKey + " during STORE"); - } else { - spiller.fillRegister(targetReg); - } - - spiller.fillRegister(valueReg); - - if (!targetReg.equals(valueReg)) { - String asm = compiler.cpuProfile.getPattern("move_reg").assemblyTemplate.get(0) - .replace("{dest}", targetReg) - .replace("{src}", valueReg); - compiler.assemblyCode.add(" " + asm); - registerAllocator.freeRegister(valueReg); - } - - spiller.markRegisterModified(targetReg); - spiller.updateRegisterDefinitionDepth(targetReg, compiler.getCurrentLoopDepth()); - spiller.trackRegisterUsage(targetReg); - } - - public void compileLoadLocal(int slotIndex, Map localRegisterMap) { - String varRegKey = "local_" + slotIndex; - String varReg = localRegisterMap.get(varRegKey); - - if (varReg == null) { - cod.debug.DebugSystem.error("MTOT_REG", "Register for " + varRegKey + " is null during LOAD! Recovering by allocating new register and assuming value 0."); - varReg = registerAllocator.allocateRegister(); - localRegisterMap.put(varRegKey, varReg); - spiller.mapSlotToRegister(slotIndex, varReg); - cod.compiler.MTOTRegistry.InstructionPattern p = compiler.cpuProfile.getPattern("load_immediate_int"); - compiler.assemblyCode.add(" " + p.assemblyTemplate.get(0).replace("{dest}", varReg).replace("{value}", "0") + " " + compiler.cpuProfile.syntax.commentMarker + " WARNING: Used uninitialized local slot " + slotIndex); - spiller.markRegisterModified(varReg); - spiller.updateRegisterDefinitionDepth(varReg, compiler.getCurrentLoopDepth()); - } else { - spiller.fillRegister(varReg); - } - - String tempReg = registerAllocator.allocateRegister(Collections.singleton(varReg)); - String asm = compiler.cpuProfile.getPattern("move_reg").assemblyTemplate.get(0) - .replace("{dest}", tempReg) - .replace("{src}", varReg); - compiler.assemblyCode.add(" " + asm); - - operandStack.pushFromRegister(tempReg); - spiller.markRegisterModified(tempReg); - spiller.trackRegisterUsage(varReg); - } - - public void compileStoreSlot(Object operand, Map localRegisterMap) { - if (operand instanceof Integer) { - int slotIndex = ((Integer) operand).intValue(); - compileStoreLocal(slotIndex, localRegisterMap); - String location = localRegisterMap.get("local_" + slotIndex); - if (location != null) { - slotLocations.put(Integer.valueOf(slotIndex), location); - cod.debug.DebugSystem.debug("MTOT_SLOT", "Recorded register location for slot index " + slotIndex + ": " + location); - } else { - cod.debug.DebugSystem.warn("MTOT_SLOT", "Cannot determine register location for slot index: " + slotIndex); - int offset = spiller.getSpillOffsetForSlotIndex(slotIndex); - if (offset != Integer.MIN_VALUE) { - slotLocations.put(Integer.valueOf(slotIndex), "spill_" + offset); - cod.debug.DebugSystem.debug("MTOT_SLOT", "Recorded spill location for slot index " + slotIndex + ": spill_" + offset); - } else { - cod.debug.DebugSystem.warn("MTOT_SLOT", "Cannot determine any location for slot index: " + slotIndex); - } - } - } else { - cod.debug.DebugSystem.error("MTOT", "STORE_SLOT operand is not an Integer index: " + operand); - } - } -} \ No newline at end of file diff --git a/src/main/java/cod/compiler/natives/MethodCallCompiler.java b/src/main/java/cod/compiler/natives/MethodCallCompiler.java deleted file mode 100644 index 8a5867ee..00000000 --- a/src/main/java/cod/compiler/natives/MethodCallCompiler.java +++ /dev/null @@ -1,306 +0,0 @@ -package cod.compiler.natives; - -import cod.compiler.MTOTNativeCompiler; -import cod.compiler.RegisterManager; -import cod.compiler.BytecodeInstruction; -import java.util.*; - -public class MethodCallCompiler { - private final MTOTNativeCompiler compiler; - private final cod.compiler.natives.OperandStack operandStack; - private final RegisterManager.RegisterAllocator registerAllocator; - private final RegisterManager.RegisterSpiller spiller; - - public MethodCallCompiler(MTOTNativeCompiler compiler) { - this.compiler = compiler; - this.operandStack = compiler.operandStack; - this.registerAllocator = compiler.registerManager.getAllocator(); - this.spiller = compiler.registerManager.getSpiller(); - } - - public void compileCall(BytecodeInstruction instr, java.util.List bytecode, int index, java.util.Map localRegisterMap) { - String methodName = (String) instr.operand; - int argCount = countArgsForCall(bytecode, index); - cod.debug.DebugSystem.debug("MTOT", "Compiling call to " + methodName + " with " + argCount + " arguments."); - - java.util.List argValueRegs = new java.util.ArrayList(); - for (int i = 0; i < argCount; i++) { - argValueRegs.add(operandStack.popToRegister()); - } - java.util.Collections.reverse(argValueRegs); - - java.util.Set excludeArgs = new java.util.HashSet(); - excludeArgs.add(compiler.argumentRegisters.get(0)); - java.util.List abiArgsUsedForParams = new java.util.ArrayList(); - - int argStartIndex = (compiler.cpuProfile.architecture.equals("x86_64")) ? 0 : 1; - - for (int i = 0; i < argCount; i++) { - int abiArgIndex = i + argStartIndex; - if (abiArgIndex < compiler.argumentRegisters.size()) { - String abiArgReg = compiler.argumentRegisters.get(abiArgIndex); - if (compiler.cpuProfile.architecture.equals("x86_64") && abiArgReg.equals(cod.compiler.MTOTRegistry.x86_64Registers.rax)) { - cod.debug.DebugSystem.warn("MTOT", "x86 ABI does not use rax for arguments. Skipping arg " + i); - abiArgIndex++; - if (abiArgIndex >= compiler.argumentRegisters.size()) continue; - abiArgReg = compiler.argumentRegisters.get(abiArgIndex); - } - excludeArgs.add(abiArgReg); - abiArgsUsedForParams.add(abiArgReg); - } - } - - java.util.Set regsToSave = compiler.spillCallerSavedRegisters(excludeArgs); - - for (int i = 0; i < argCount; i++) { - if (i < abiArgsUsedForParams.size()) { - String abiArgReg = abiArgsUsedForParams.get(i); - String valueReg = argValueRegs.get(i); - spiller.fillRegister(valueReg); - registerAllocator.markRegisterUsed(abiArgReg); - if (!abiArgReg.equals(valueReg)) { - compiler.assemblyCode.add(" mov " + abiArgReg + ", " + valueReg + " " + compiler.cpuProfile.syntax.commentMarker + " Setup arg " + (i + 1)); - } - } else { - cod.debug.DebugSystem.warn("MTOT", "Argument " + i + " stack passing not implemented for call to " + methodName); - } - } - - String thisAbiArgReg = (compiler.cpuProfile.architecture.equals("x86_64")) ? - cod.compiler.MTOTRegistry.x86_64Registers.rdi : compiler.argumentRegisters.get(0); - spiller.fillRegister(compiler.thisRegister); - registerAllocator.markRegisterUsed(thisAbiArgReg); - if (!thisAbiArgReg.equals(compiler.thisRegister)) { - compiler.assemblyCode.add(" mov " + thisAbiArgReg + ", " + compiler.thisRegister + " " + compiler.cpuProfile.syntax.commentMarker + " Setup 'this' pointer"); - } - - for (int i = 0; i < argValueRegs.size(); i++) { - String valueReg = argValueRegs.get(i); - boolean isUsedForArg = (i < abiArgsUsedForParams.size() && valueReg.equals(abiArgsUsedForParams.get(i))); - if (!isUsedForArg) { - registerAllocator.freeRegister(valueReg); - } - } - - String callAsm = compiler.cpuProfile.getPattern("call").assemblyTemplate.get(0).replace("{name}", methodName); - compiler.assemblyCode.add(" " + callAsm); - - compiler.fillCallerSavedRegisters(regsToSave); - - for (String reg : abiArgsUsedForParams) { - registerAllocator.freeRegister(reg); - } - - String returnAbiReg = (compiler.cpuProfile.architecture.equals("x86_64")) ? - cod.compiler.MTOTRegistry.x86_64Registers.rax : compiler.argumentRegisters.get(0); - - java.util.Set avoidReturnReg = java.util.Collections.singleton(returnAbiReg); - String resultReg = registerAllocator.allocateRegister(avoidReturnReg); - compiler.assemblyCode.add(" mov " + resultReg + ", " + returnAbiReg + " " + compiler.cpuProfile.syntax.commentMarker + " Get result"); - operandStack.pushFromRegister(resultReg); - spiller.markRegisterModified(resultReg); - - if (!resultReg.equals(returnAbiReg)) { - registerAllocator.freeRegister(returnAbiReg); - } - } - - public void compileCallSlots(BytecodeInstruction instr, java.util.List bytecode, int index, java.util.Map localRegisterMap) { - Object[] operand = (Object[]) instr.operand; - String methodName = (String) operand[0]; - int numSlots = ((Integer) operand[1]).intValue(); - int argCount = countArgsForCall(bytecode, index); - cod.debug.DebugSystem.debug("MTOT", "Compiling CALL_SLOTS to " + methodName + " with " + argCount + " arguments, expecting " + numSlots + " slots."); - - java.util.List argValueRegs = new java.util.ArrayList(); - for (int i = 0; i < argCount; i++) { - argValueRegs.add(operandStack.popToRegister()); - } - java.util.Collections.reverse(argValueRegs); - - java.util.Set excludeArgs = new java.util.HashSet(); - - String thisAbiArgReg = (compiler.cpuProfile.architecture.equals("x86_64")) ? - cod.compiler.MTOTRegistry.x86_64Registers.rdi : compiler.argumentRegisters.get(0); - excludeArgs.add(thisAbiArgReg); - - java.util.List abiArgsUsedForParams = new java.util.ArrayList(); - - int argStartIndex = (compiler.cpuProfile.architecture.equals("x86_64")) ? 1 : 1; - - for (int i = 0; i < argCount; i++) { - int abiArgIndex = i + argStartIndex; - if (abiArgIndex < compiler.argumentRegisters.size()) { - String abiArgReg = compiler.argumentRegisters.get(abiArgIndex); - if (compiler.cpuProfile.architecture.equals("x86_64") && abiArgReg.equals(cod.compiler.MTOTRegistry.x86_64Registers.rax)) { - cod.debug.DebugSystem.warn("MTOT", "x86 ABI does not use rax for arguments. Skipping arg " + i); - abiArgIndex++; - if (abiArgIndex >= compiler.argumentRegisters.size()) continue; - abiArgReg = compiler.argumentRegisters.get(abiArgIndex); - } - excludeArgs.add(abiArgReg); - abiArgsUsedForParams.add(abiArgReg); - } - } - - java.util.Set regsToSave = compiler.spillCallerSavedRegisters(excludeArgs); - - for (int i = 0; i < argCount; i++) { - if (i < abiArgsUsedForParams.size()) { - String abiArgReg = abiArgsUsedForParams.get(i); - String valueReg = argValueRegs.get(i); - spiller.fillRegister(valueReg); - registerAllocator.markRegisterUsed(abiArgReg); - if (!abiArgReg.equals(valueReg)) { - compiler.assemblyCode.add(" mov " + abiArgReg + ", " + valueReg + " " + compiler.cpuProfile.syntax.commentMarker + " Setup arg " + (i + 1)); - } - } else { - cod.debug.DebugSystem.warn("MTOT", "Argument " + i + " stack passing not implemented for CALL_SLOTS to " + methodName); - } - } - - spiller.fillRegister(compiler.thisRegister); - registerAllocator.markRegisterUsed(thisAbiArgReg); - if (!thisAbiArgReg.equals(compiler.thisRegister)) { - compiler.assemblyCode.add(" mov " + thisAbiArgReg + ", " + compiler.thisRegister + " " + compiler.cpuProfile.syntax.commentMarker + " Setup 'this' pointer"); - } - - for (int i = 0; i < argValueRegs.size(); i++) { - String valueReg = argValueRegs.get(i); - boolean isUsedForArg = (i < abiArgsUsedForParams.size() && valueReg.equals(abiArgsUsedForParams.get(i))); - if (!isUsedForArg) { - registerAllocator.freeRegister(valueReg); - } - } - - String callAsm = compiler.cpuProfile.getPattern("call").assemblyTemplate.get(0).replace("{name}", methodName); - compiler.assemblyCode.add(" " + callAsm); - - compiler.fillCallerSavedRegisters(regsToSave); - - java.util.Set returnSlotRegs = new java.util.HashSet(); - - if (compiler.cpuProfile.architecture.equals("x86_64")) { - String ret0 = cod.compiler.MTOTRegistry.x86_64Registers.rax; - String ret1 = cod.compiler.MTOTRegistry.x86_64Registers.rdx; - returnSlotRegs.add(ret0); - if (numSlots > 1) returnSlotRegs.add(ret1); - - for (String reg : abiArgsUsedForParams) { - if (!reg.equals(ret0) && (numSlots < 2 || !reg.equals(ret1))) { - registerAllocator.freeRegister(reg); - } - } - if (!thisAbiArgReg.equals(ret0) && (numSlots < 2 || !thisAbiArgReg.equals(ret1))) { - registerAllocator.freeRegister(thisAbiArgReg); - } - } else { - for (int i = 0; i < numSlots && i < compiler.argumentRegisters.size(); i++) { - returnSlotRegs.add(compiler.argumentRegisters.get(i)); - } - for (String reg : abiArgsUsedForParams) { - if (!returnSlotRegs.contains(reg)) { - registerAllocator.freeRegister(reg); - } - } - if (!returnSlotRegs.contains(thisAbiArgReg)) { - registerAllocator.freeRegister(thisAbiArgReg); - } - } - - java.util.Set avoidReturnRegs = new java.util.HashSet(returnSlotRegs); - for (int i = 0; i < numSlots; i++) { - String returnRegAbi; - if (compiler.cpuProfile.architecture.equals("x86_64")) { - if (i == 0) returnRegAbi = cod.compiler.MTOTRegistry.x86_64Registers.rax; - else if (i == 1) returnRegAbi = cod.compiler.MTOTRegistry.x86_64Registers.rdx; - else { - cod.debug.DebugSystem.error("MTOT_SLOT", "Requested slot " + i + " but x86 only supports 2 return registers (rax, rdx)!"); - returnRegAbi = null; - } - } else { - if (i >= compiler.argumentRegisters.size()) { - cod.debug.DebugSystem.error("MTOT_SLOT", "Requested slot " + i + " but only " + compiler.argumentRegisters.size() + " return registers exist!"); - returnRegAbi = null; - } else { - returnRegAbi = compiler.argumentRegisters.get(i); - } - } - - if (returnRegAbi == null) { - String errReg = registerAllocator.allocateRegister(avoidReturnRegs); - cod.compiler.MTOTRegistry.InstructionPattern p = compiler.cpuProfile.getPattern("load_immediate_int"); - compiler.assemblyCode.add(" " + p.assemblyTemplate.get(0).replace("{dest}", errReg).replace("{value}", "0") + " " + compiler.cpuProfile.syntax.commentMarker + " ERROR: Missing return slot " + i); - operandStack.pushFromRegister(errReg); - spiller.markRegisterModified(errReg); - avoidReturnRegs.add(errReg); - continue; - } - - String resultReg = registerAllocator.allocateRegister(avoidReturnRegs); - compiler.assemblyCode.add(" mov " + resultReg + ", " + returnRegAbi + " " + compiler.cpuProfile.syntax.commentMarker + " Get result slot " + i); - operandStack.pushFromRegister(resultReg); - spiller.markRegisterModified(resultReg); - - if (!resultReg.equals(returnRegAbi)) { - registerAllocator.freeRegister(returnRegAbi); - } - avoidReturnRegs.remove(returnRegAbi); - avoidReturnRegs.add(resultReg); - } - } - - private int countArgsForCall(java.util.List bytecode, int callInstructionIndex) { - int required_depth = 0; - int max_required_depth = 0; - for (int i = callInstructionIndex - 1; i >= 0; i--) { - BytecodeInstruction instr = bytecode.get(i); - BytecodeInstruction.Opcode op = instr.opcode; - int pops = 0; - int pushes = 0; - - if ((op.ordinal() >= BytecodeInstruction.Opcode.PUSH_INT.ordinal() && op.ordinal() <= BytecodeInstruction.Opcode.PUSH_NULL.ordinal()) - || op == BytecodeInstruction.Opcode.LOAD_LOCAL - || op == BytecodeInstruction.Opcode.LOAD_FIELD - || op == BytecodeInstruction.Opcode.ARRAY_NEW - || op == BytecodeInstruction.Opcode.READ_INPUT - || op == BytecodeInstruction.Opcode.CALL) { - pushes = 1; - } - else if (op == BytecodeInstruction.Opcode.DUP) { pops = 1; pushes = 2; } - else if (op == BytecodeInstruction.Opcode.SWAP) { pops = 2; pushes = 2; } - else if (op == BytecodeInstruction.Opcode.CALL_SLOTS) { Object[] callOperand = (Object[]) instr.operand; pushes = ((Integer) callOperand[1]).intValue(); } - else if ((op.ordinal() >= BytecodeInstruction.Opcode.ADD_INT.ordinal() && op.ordinal() <= BytecodeInstruction.Opcode.CMP_GE_INT.ordinal()) - || op == BytecodeInstruction.Opcode.CONCAT_STRING - || op == BytecodeInstruction.Opcode.ARRAY_LOAD) { - pops = 2; pushes = 1; - } else if (op == BytecodeInstruction.Opcode.NEG_INT - || op == BytecodeInstruction.Opcode.INT_TO_STRING) { - pops = 1; pushes = 1; - } - else if (op == BytecodeInstruction.Opcode.ARRAY_STORE) { pops = 3; } - else if (op == BytecodeInstruction.Opcode.POP - || op == BytecodeInstruction.Opcode.PRINT - || op == BytecodeInstruction.Opcode.STORE_LOCAL - || op == BytecodeInstruction.Opcode.STORE_FIELD - || op == BytecodeInstruction.Opcode.STORE_SLOT - || op == BytecodeInstruction.Opcode.JMP_IF_FALSE - || op == BytecodeInstruction.Opcode.JMP_IF_TRUE) { - pops = 1; - } - else if (op == BytecodeInstruction.Opcode.JMP - || op == BytecodeInstruction.Opcode.LABEL - || op == BytecodeInstruction.Opcode.RET) { - break; - } - - required_depth -= pushes; - required_depth += pops; - if (required_depth < 0) { - max_required_depth++; - required_depth = 0; - } - } - return Math.max(0, max_required_depth); - } -} \ No newline at end of file diff --git a/src/main/java/cod/compiler/natives/OperandStack.java b/src/main/java/cod/compiler/natives/OperandStack.java deleted file mode 100644 index 5fccbfc1..00000000 --- a/src/main/java/cod/compiler/natives/OperandStack.java +++ /dev/null @@ -1,60 +0,0 @@ -package cod.compiler.natives; - -import cod.compiler.MTOTNativeCompiler; -import cod.compiler.RegisterManager; - -public class OperandStack { - private final java.util.Stack stack = new java.util.Stack(); - private final MTOTNativeCompiler compiler; - private final RegisterManager.RegisterAllocator registerAllocator; - private final RegisterManager.RegisterSpiller spiller; - - public OperandStack(MTOTNativeCompiler compiler) { - this.compiler = compiler; - this.registerAllocator = compiler.registerManager.getAllocator(); - this.spiller = compiler.registerManager.getSpiller(); - } - - public String popToRegister() { - if (stack.isEmpty()) { - cod.debug.DebugSystem.warn("OPERAND_STACK", "Popping from empty stack - allocating new register"); - String reg = registerAllocator.allocateRegister(); - spiller.updateRegisterDefinitionDepth(reg, compiler.getCurrentLoopDepth()); - return reg; - } - return stack.pop(); - } - - public void pushFromRegister(String reg) { - stack.push(reg); - spiller.updateRegisterDefinitionDepth(reg, compiler.getCurrentLoopDepth()); - } - - public String peek() { - return stack.isEmpty() ? null : stack.peek(); - } - - public boolean isEmpty() { - return stack.isEmpty(); - } - - public int size() { - return stack.size(); - } - - public void clear() { - for (String reg : stack) { - if (reg != null) { - registerAllocator.freeRegister(reg); - } - } - stack.clear(); - } - - public String[] popTwoOperands() { - String[] operands = new String[2]; - operands[1] = popToRegister(); - operands[0] = popToRegister(); - return operands; - } -} \ No newline at end of file diff --git a/src/main/java/cod/compiler/natives/OperationCompiler.java b/src/main/java/cod/compiler/natives/OperationCompiler.java deleted file mode 100644 index b86da6b3..00000000 --- a/src/main/java/cod/compiler/natives/OperationCompiler.java +++ /dev/null @@ -1,82 +0,0 @@ -package cod.compiler.natives; - -import cod.compiler.MTOTNativeCompiler; -import cod.compiler.RegisterManager; -import java.util.*; - -public class OperationCompiler { - private final MTOTNativeCompiler compiler; - private final cod.compiler.natives.OperandStack operandStack; - private final RegisterManager.RegisterAllocator registerAllocator; - private final RegisterManager.RegisterSpiller spiller; - - public OperationCompiler(MTOTNativeCompiler compiler) { - this.compiler = compiler; - this.operandStack = compiler.operandStack; - this.registerAllocator = compiler.registerManager.getAllocator(); - this.spiller = compiler.registerManager.getSpiller(); - } - - public void generateBinaryOp(String patternName) { - cod.compiler.MTOTRegistry.InstructionPattern p = compiler.cpuProfile.getPattern(patternName); - if (p == null) throw new RuntimeException("No pattern for " + patternName); - - String[] ops = operandStack.popTwoOperands(); - String l = ops[0], r = ops[1]; - Set avoid = new HashSet(Arrays.asList(l, r)); - String res = registerAllocator.allocateRegister(avoid); - - spiller.fillRegister(l); - spiller.fillRegister(r); - - Set clobberedRegs = new HashSet(); - if (p.requiredRegisters != null) { - for (String clobbered : p.requiredRegisters) { - if (clobbered.equals("al")) clobbered = cod.compiler.MTOTRegistry.x86_64Registers.rax; - registerAllocator.markRegisterUsed(clobbered); - clobberedRegs.add(clobbered); - } - } - - for (String t : p.assemblyTemplate) { - String asm = t.replace("{dest}", res).replace("{src1}", l).replace("{src2}", r); - compiler.assemblyCode.add(" " + asm); - } - - for (String clobbered : clobberedRegs) { - if (patternName.equals("mod_int") && clobbered.equals(cod.compiler.MTOTRegistry.x86_64Registers.rax)) { - registerAllocator.freeRegister(clobbered); - } - else if (patternName.equals("div_int") && clobbered.equals(cod.compiler.MTOTRegistry.x86_64Registers.rdx)) { - registerAllocator.freeRegister(clobbered); - } - else if (!clobbered.equals(res)) { - registerAllocator.freeRegister(clobbered); - } - } - - operandStack.pushFromRegister(res); - spiller.markRegisterModified(res); - registerAllocator.freeRegister(l); - registerAllocator.freeRegister(r); - } - - public void generateUnaryOp(String patternName) { - cod.compiler.MTOTRegistry.InstructionPattern pattern = compiler.cpuProfile.getPattern(patternName); - if (pattern == null) { throw new RuntimeException("No pattern for unary op: " + patternName); } - - String operandReg = operandStack.popToRegister(); - String resultReg = registerAllocator.allocateRegister(Collections.singleton(operandReg)); - - spiller.fillRegister(operandReg); - - for (String template : pattern.assemblyTemplate) { - String asm = template.replace("{dest}", resultReg).replace("{src}", operandReg); - compiler.assemblyCode.add(" " + asm); - } - - operandStack.pushFromRegister(resultReg); - spiller.markRegisterModified(resultReg); - registerAllocator.freeRegister(operandReg); - } -} \ No newline at end of file diff --git a/src/main/java/cod/compiler/natives/RuntimeCallHelper.java b/src/main/java/cod/compiler/natives/RuntimeCallHelper.java deleted file mode 100644 index ef7ca566..00000000 --- a/src/main/java/cod/compiler/natives/RuntimeCallHelper.java +++ /dev/null @@ -1,121 +0,0 @@ -package cod.compiler.natives; - -import cod.compiler.MTOTNativeCompiler; -import cod.compiler.RegisterManager; -import java.util.*; - -public class RuntimeCallHelper { - private final MTOTNativeCompiler compiler; - private final cod.compiler.natives.OperandStack operandStack; - private final RegisterManager.RegisterAllocator registerAllocator; - private final RegisterManager.RegisterSpiller spiller; - - public RuntimeCallHelper(MTOTNativeCompiler compiler) { - this.compiler = compiler; - this.operandStack = compiler.operandStack; - this.registerAllocator = compiler.registerManager.getAllocator(); - this.spiller = compiler.registerManager.getSpiller(); - } - - public void compileRuntimeCall(String functionName, int argCount, boolean hasReturnValue) { - List argValueRegs = new ArrayList(); - Set excludeArgs = new HashSet(); - List abiArgsUsed = new ArrayList(); - - int argStartIndex = (compiler.cpuProfile.architecture.equals("x86_64")) ? 0 : 0; - - for (int i = 0; i < argCount; i++) { - if (i + argStartIndex >= compiler.argumentRegisters.size()) { - cod.debug.DebugSystem.error("MTOT", "Runtime call " + functionName + " needs arg " + i + " but ABI only has " + compiler.argumentRegisters.size()); - break; - } - argValueRegs.add(operandStack.popToRegister()); - String abiArg = compiler.argumentRegisters.get(i + argStartIndex); - excludeArgs.add(abiArg); - abiArgsUsed.add(abiArg); - } - Collections.reverse(argValueRegs); - - Set regsToSave = compiler.spillCallerSavedRegisters(excludeArgs); - - for (int i = 0; i < argValueRegs.size(); i++) { - String valueReg = argValueRegs.get(i); - String abiArg = abiArgsUsed.get(i); - spiller.fillRegister(valueReg); - registerAllocator.markRegisterUsed(abiArg); - if (!abiArg.equals(valueReg)) { - compiler.assemblyCode.add(" mov " + abiArg + ", " + valueReg); - } - } - - String callAsm = compiler.cpuProfile.getPattern("call").assemblyTemplate.get(0).replace("{name}", functionName); - compiler.assemblyCode.add(" " + callAsm + " " + compiler.cpuProfile.syntax.commentMarker + " Call runtime helper"); - - compiler.fillCallerSavedRegisters(regsToSave); - - String returnAbiReg = (compiler.cpuProfile.architecture.equals("x86_64")) ? - cod.compiler.MTOTRegistry.x86_64Registers.rax : compiler.argumentRegisters.get(0); - - if (hasReturnValue) { - Set avoidReturnRegs = new HashSet(abiArgsUsed); - avoidReturnRegs.add(returnAbiReg); - - String resultReg = registerAllocator.allocateRegister(avoidReturnRegs); - compiler.assemblyCode.add(" mov " + resultReg + ", " + returnAbiReg + " " + compiler.cpuProfile.syntax.commentMarker + " Get result"); - operandStack.pushFromRegister(resultReg); - spiller.markRegisterModified(resultReg); - } - - for (int i = 0; i < abiArgsUsed.size(); i++) { - String abiArg = abiArgsUsed.get(i); - String valueReg = argValueRegs.get(i); - - if (!abiArg.equals(valueReg)) { - registerAllocator.freeRegister(valueReg); - } - - boolean neededForResult = hasReturnValue && abiArg.equals(returnAbiReg) && operandStack.peek() != null && operandStack.peek().equals(returnAbiReg); - if (!neededForResult) { - registerAllocator.freeRegister(abiArg); - } - } - } - - public void compileReadInput(String expectedType) { - String typeLabel = compiler.generateDataLabel("input_type"); - String directive = compiler.cpuProfile.syntax.stringDirective - .replace("{label}", typeLabel) - .replace("{value}", compiler.escapeString(expectedType)); - compiler.dataSection.add(directive); - - String abiArg0 = (compiler.cpuProfile.architecture.equals("x86_64")) ? - cod.compiler.MTOTRegistry.x86_64Registers.rdi : compiler.argumentRegisters.get(0); - - Set excludeArgs = new HashSet(); - excludeArgs.add(abiArg0); - - Set regsToSave = compiler.spillCallerSavedRegisters(excludeArgs); - - registerAllocator.markRegisterUsed(abiArg0); - cod.compiler.MTOTRegistry.InstructionPattern loadAddrPattern = compiler.cpuProfile.getPattern("load_address"); - for (String t : loadAddrPattern.assemblyTemplate) { - compiler.assemblyCode.add(" " + t.replace("{dest}", abiArg0).replace("{label}", typeLabel)); - } - - String callAsm = compiler.cpuProfile.getPattern("call").assemblyTemplate.get(0).replace("{name}", "runtime_read_input"); - compiler.assemblyCode.add(" " + callAsm + " " + compiler.cpuProfile.syntax.commentMarker + " Call runtime helper (expects type* in arg0)"); - - compiler.fillCallerSavedRegisters(regsToSave); - - String returnAbiReg = (compiler.cpuProfile.architecture.equals("x86_64")) ? - cod.compiler.MTOTRegistry.x86_64Registers.rax : compiler.argumentRegisters.get(0); - - Set avoidReturnRegs = new HashSet(Collections.singletonList(returnAbiReg)); - String resultReg = registerAllocator.allocateRegister(avoidReturnRegs); - compiler.assemblyCode.add(" mov " + resultReg + ", " + returnAbiReg + " " + compiler.cpuProfile.syntax.commentMarker + " Get input result"); - operandStack.pushFromRegister(resultReg); - spiller.markRegisterModified(resultReg); - - if (!resultReg.equals(returnAbiReg)) registerAllocator.freeRegister(returnAbiReg); - } -} From d864dfbbac35902dac5549629d8e1d8100a90529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:56:13 +0800 Subject: [PATCH 07/54] Delete src/main/java/cod/compiler/BytecodeCompiler.java --- .../java/cod/compiler/BytecodeCompiler.java | 565 ------------------ 1 file changed, 565 deletions(-) delete mode 100644 src/main/java/cod/compiler/BytecodeCompiler.java diff --git a/src/main/java/cod/compiler/BytecodeCompiler.java b/src/main/java/cod/compiler/BytecodeCompiler.java deleted file mode 100644 index 91e7b20c..00000000 --- a/src/main/java/cod/compiler/BytecodeCompiler.java +++ /dev/null @@ -1,565 +0,0 @@ -package cod.compiler; - -import cod.ast.nodes.*; -import cod.debug.DebugSystem; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class BytecodeCompiler { - private List code = new ArrayList(); - private Map variableSlots = new HashMap(); - private int nextSlot = 0; - private int labelCounter = 0; - - // Pattern to parse combined step operators like "*+2", "/-3", "*2", "+1", "-1" etc. - // Group 1: First operator (*, /, +, -) - Optional - // Group 2: First number (digits, potentially signed like "+2" or "-3") - Optional (defaults based on op1) - private static final Pattern STEP_OP_PATTERN = Pattern.compile("^([*/+-])?([+-]?\\d+)?$"); - - - // --- Helper Method --- - /** - * Checks if an expression node represents a constant integer value - * (either a direct literal or a negated literal) and returns it. - * Returns null if it's not a constant integer. - */ - private Integer getConstantIntValue(ExprNode expr) { - if (expr == null) { - return null; - } - if (expr.value instanceof Integer) { - return (Integer) expr.value; - } - // Check for negated integer literal (e.g., -5) - if (expr instanceof UnaryNode) { - UnaryNode unary = (UnaryNode) expr; - if ("-".equals(unary.op) && unary.operand != null && unary.operand.value instanceof Integer) { - return -(Integer) unary.operand.value; - } - } - return null; // Not a constant integer we can easily evaluate - } - - // --- Helper to check if a step expression is multiplicative/divisive --- - private boolean isMultDivStep(ExprNode expr) { - if (expr == null) return false; - - if (expr.name != null && expr.value == null) { - String op = expr.name.trim(); - // FIX: Just check the prefix. This correctly identifies "*2" AND "*num" - // as multiplicative, while "2" and "num" are not. - if (op.startsWith("*") || op.startsWith("/")) return true; - } else if (expr instanceof BinaryOpNode) { - String op = ((BinaryOpNode)expr).op; - // Check if the root operation is mult/div OR if it involves multiplicative operator strings - if ("*".equals(op) || "/".equals(op) || "%".equals(op)) return true; - // Recursively check if either side implies multiplication/division relative to 'i' - // This handles cases like `by *2 + 1` (root is '+', but involves '*') - if (isMultDivStep(((BinaryOpNode)expr).left)) return true; - if (isMultDivStep(((BinaryOpNode)expr).right)) return true; - } - // Assignment steps like 'i *= 2' are handled separately in compileForLoop - return false; - } - - - public BytecodeProgram compile(ProgramNode program) { - DebugSystem.info("BYTECODE", "Starting MTOT bytecode compilation"); - BytecodeProgram result = new BytecodeProgram(); - if (program.unit != null) { - compileUnit(program.unit, result); - } - int totalInstructions = 0; - for (List methodCode : result.getMethods().values()) { - totalInstructions += methodCode.size(); - } - DebugSystem.info("BYTECODE", "Compilation complete: " + totalInstructions + - " instructions across " + result.getMethods().size() + " methods"); - return result; - } - - private void compileUnit(UnitNode unit, BytecodeProgram program) { - for (TypeNode type : unit.types) { - compileType(type, program); - } - } - - private void compileType(TypeNode type, BytecodeProgram program) { - for (MethodNode method : type.methods) { - compileMethod(method, program); - } - } - - private void compileMethod(MethodNode method, BytecodeProgram program) { - DebugSystem.debug("BYTECODE", "=== COMPILING METHOD: " + method.name + " ==="); - code.clear(); - variableSlots.clear(); - nextSlot = 0; - labelCounter = 0; - - // Allocate slots for parameters - for (ParamNode param : method.parameters) { - allocateVariableSlot(param.name); - DebugSystem.debug("BYTECODE_VARS", "Allocated slot " + (nextSlot - 1) + " for param: " + param.name); - } - - // Allocate slots for return values - for (SlotNode slot : method.returnSlots) { - allocateVariableSlot(slot.name); - DebugSystem.debug("BYTECODE_VARS", "Allocated slot " + (nextSlot - 1) + " for return slot: " + slot.name); - } - - // Compile method body - for (StatementNode stmt : method.body) { - compileStatement(stmt); - } - - // FIXED: Proper return slot handling - if (method.returnSlots.isEmpty()) { - // No return slots - push null - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_NULL)); - } else { - // Return values from slots - // Push return values in reverse order (for multiple return values) - for (int i = method.returnSlots.size() - 1; i >= 0; i--) { - String slotName = method.returnSlots.get(i).name; - Integer slotIndex = variableSlots.get(slotName); - if (slotIndex != null) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, slotIndex)); - DebugSystem.debug("BYTECODE", "Loading return slot '" + slotName + "' from slot " + slotIndex); - } else { - DebugSystem.error("BYTECODE", "Return slot '" + slotName + "' not found in variable slots!"); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_NULL)); - } - } - DebugSystem.debug("BYTECODE", "Method " + method.name + " returning " + method.returnSlots.size() + " slot values"); - } - - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.RET)); - program.addMethod(method.name, new ArrayList(code)); - DebugSystem.debug("BYTECODE", "=== FINISHED METHOD: " + method.name + " (" + code.size() + " instructions) ==="); -} - - private void compileStatement(StatementNode stmt) { - if (stmt instanceof VarNode) { compileVariableDeclaration((VarNode) stmt); } - else if (stmt instanceof AssignmentNode) { compileAssignment((AssignmentNode) stmt); } - else if (stmt instanceof SlotAssignmentNode) { compileSlotAssignment((SlotAssignmentNode) stmt); } - else if (stmt instanceof OutputNode) { compileOutput((OutputNode) stmt); } - else if (stmt instanceof IfNode) { compileIfStatement((IfNode) stmt); } - else if (stmt instanceof ForNode) { compileForLoop((ForNode) stmt); } - else if (stmt instanceof MethodCallNode) { - compileMethodCall((MethodCallNode) stmt); - // Basic pop logic (needs refinement based on AST parent info) - if (!isExpressionUsed(stmt, (MethodCallNode)stmt)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.POP)); } - } else if (stmt instanceof ReturnSlotAssignmentNode) { compileReturnSlotAssignment((ReturnSlotAssignmentNode) stmt); } - else if (stmt instanceof InputNode) { compileInput((InputNode) stmt); } - else if (stmt instanceof FieldNode) { /* Ignore */ } - else if (stmt instanceof ExprNode) { - compileExpression((ExprNode) stmt); - if (!isExpressionUsed(stmt, null)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.POP)); } - } else { DebugSystem.warn("BYTECODE", "Unhandled statement type: " + stmt.getClass().getSimpleName()); } - } - - // Crude check, needs AST parent info to be accurate - private boolean isExpressionUsed(StatementNode stmt, MethodCallNode call) { - // If it's a method call that specifies slots, assume it's used - if (call != null && call.slotNames != null && !call.slotNames.isEmpty()) { - return true; - } - // HACK: Don't pop 'main' - if (call != null && "main".equals(call.name)) { - return true; - } - - return false; // Defaulting to pop if usage isn't obvious - } - - - private void compileSlotAssignment(SlotAssignmentNode assign) { - compileExpression(assign.value); - Integer slotIndex = variableSlots.get(assign.slotName); - if (slotIndex != null) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_SLOT, slotIndex)); } - else { DebugSystem.error("BYTECODE", "Slot '" + assign.slotName + "' not found..."); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.POP)); } - } - - private void compileAssignment(AssignmentNode assign) { - if (assign.left instanceof IndexAccessNode) { /* Array store */ IndexAccessNode access = (IndexAccessNode) assign.left; compileExpression(access.array); compileExpression(access.index); compileExpression(assign.right); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ARRAY_STORE)); } - else if (assign.left.name != null) { /* Variable store */ String targetName = assign.left.name; compileExpression(assign.right); int slot = getOrAllocateVariableSlot(targetName); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, slot)); } - else { DebugSystem.warn("BYTECODE", "Unhandled assignment target..."); compileExpression(assign.right); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.POP)); } - } - - private void compileVariableDeclaration(VarNode var) { - int slot = getOrAllocateVariableSlot(var.name); - if (var.value != null) { compileExpression(var.value); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, slot)); } - else { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_NULL)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, slot)); } - } - - private void compileOutput(OutputNode output) { - if (output.arguments.isEmpty()) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_STRING, "")); } - else { compileExpression(output.arguments.get(0)); } - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PRINT)); - } - - private void compileIfStatement(IfNode ifNode) { - String elseLabel = generateLabel("else"); String endLabel = generateLabel("endif"); compileExpression(ifNode.condition); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP_IF_FALSE, elseLabel)); for (StatementNode stmt : ifNode.thenBlock.statements) { compileStatement(stmt); } boolean hasElse = !ifNode.elseBlock.statements.isEmpty(); if (hasElse) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP, endLabel)); } placeLabel(elseLabel); if (hasElse) { for (StatementNode stmt : ifNode.elseBlock.statements) { compileStatement(stmt); } } placeLabel(endLabel); - } - - // --- METHOD MODIFIED (FINAL LOOP FIX) --- - private void compileForLoop(ForNode forNode) { - int iteratorSlot = getOrAllocateVariableSlot(forNode.iterator); - int endSlot = allocateVariableSlot(forNode.iterator + "_end"); - - compileExpression(forNode.range.start); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, iteratorSlot)); - compileExpression(forNode.range.end); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, endSlot)); - - ExprNode stepExpr = forNode.range.step; - - // CASE 1: Smart Default - if (stepExpr == null) { - // (Omitted for brevity, logic is correct) - Integer startVal = getConstantIntValue(forNode.range.start); Integer endVal = getConstantIntValue(forNode.range.end); if (startVal != null && endVal != null) { boolean countUp = (startVal <= endVal); String loopBody = generateLabel("loop_body_" + (countUp ? "up" : "down")); String loopCheck = generateLabel("loop_check_" + (countUp ? "up" : "down")); String loopEnd = generateLabel("loop_end"); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP, loopCheck)); placeLabel(loopBody); for (StatementNode stmt : forNode.body.statements) { compileStatement(stmt); } code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, countUp ? 1 : -1)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ADD_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, iteratorSlot)); placeLabel(loopCheck); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, endSlot)); code.add(new BytecodeInstruction(countUp ? BytecodeInstruction.Opcode.CMP_LE_INT : BytecodeInstruction.Opcode.CMP_GE_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP_IF_TRUE, loopBody)); placeLabel(loopEnd); } else { /* Runtime check needed */ String loopBodyUp = generateLabel("loop_body_up"); String loopCheckUp = generateLabel("loop_check_up"); String loopBodyDown = generateLabel("loop_body_down"); String loopCheckDown = generateLabel("loop_check_down"); String loopEnd = generateLabel("loop_end"); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, endSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_LE_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP_IF_TRUE, loopCheckUp)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP, loopCheckDown)); placeLabel(loopBodyDown); for (StatementNode stmt : forNode.body.statements) { compileStatement(stmt); } code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, -1)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ADD_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, iteratorSlot)); placeLabel(loopCheckDown); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, endSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_GE_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP_IF_TRUE, loopBodyDown)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP, loopEnd)); placeLabel(loopBodyUp); for (StatementNode stmt : forNode.body.statements) { compileStatement(stmt); } code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, 1)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ADD_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, iteratorSlot)); placeLabel(loopCheckUp); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, endSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_LE_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP_IF_TRUE, loopBodyUp)); placeLabel(loopEnd); } - // CASE 2: Explicit Step - } else { - String loopStart = generateLabel("loop_start"); String loopContinueCheck = generateLabel("loop_cont"); String loopEnd = generateLabel("loop_end"); - - // --- Static analysis for direction --- - boolean isLikelyCountdown = false; - // (Omitted for brevity, logic is correct for basic cases) - Integer stepConst = getConstantIntValue(stepExpr); if (stepConst != null && stepConst < 0) { isLikelyCountdown = true; } else if (stepExpr instanceof UnaryNode && "-".equals(((UnaryNode)stepExpr).op)) { isLikelyCountdown = true; } else if (stepExpr instanceof BinaryOpNode) { String op = ((BinaryOpNode)stepExpr).op; if (op.equals("-=") || op.equals("/=")) { isLikelyCountdown = true; } else if (op.equals("=")) { ExprNode rhs = ((BinaryOpNode)stepExpr).right; if (rhs instanceof BinaryOpNode) { String rhsOp = ((BinaryOpNode)rhs).op; ExprNode rhsLeft = ((BinaryOpNode)rhs).left; if (rhsLeft != null && rhsLeft.name != null && rhsLeft.name.equals(forNode.iterator)) { if (rhsOp.equals("-") || rhsOp.equals("/")) { isLikelyCountdown = true; } } } else { Integer constRhs = getConstantIntValue(rhs); if(constRhs != null && constRhs < 0) isLikelyCountdown = true; } } else { if (op.equals("-") || op.equals("/")) isLikelyCountdown = true; Integer constRight = getConstantIntValue(((BinaryOpNode)stepExpr).right); if(constRight != null && constRight < 0 && (op.equals("+") || op.equals("*"))) isLikelyCountdown = true; } } else if (stepExpr.value instanceof String || stepExpr.name != null) { String op = (stepExpr.value != null) ? (String)stepExpr.value : stepExpr.name; if (op != null) { op = op.trim(); if (op.startsWith("-") || op.startsWith("/")) { isLikelyCountdown = true; } else if (op.startsWith("*") || op.startsWith("/")) { try { String numStr = op.substring(1); int value = Integer.parseInt(numStr); if (value < 0) isLikelyCountdown = true; } catch (Exception e) {} } else { try { if(Integer.parseInt(op) < 0) isLikelyCountdown = true; } catch(Exception e){} } } } - DebugSystem.debug("BYTECODE", "For-loop '" + forNode.iterator + "' (explicit step): Compile-time direction assumption -> " + (isLikelyCountdown ? "DOWN" : "UP")); - - - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP, loopContinueCheck)); - placeLabel(loopStart); - for (StatementNode stmt : forNode.body.statements) { compileStatement(stmt); } - - // --- MODIFIED STEP LOGIC (FINAL FIX) --- - - boolean isAssignment = (stepExpr instanceof BinaryOpNode && - (((BinaryOpNode)stepExpr).op.endsWith("=") || "=".equals(((BinaryOpNode)stepExpr).op))); - - if (isAssignment) { - BinaryOpNode binOp = (BinaryOpNode) stepExpr; - if ("=".equals(binOp.op)) { - // "by i = i * 2 + 1" -> RHS is the new value - compileStepRHS(binOp.right, iteratorSlot); - } else { - // "by i += 1", "by i *= 2" -> Load i, compile RHS, apply op - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); - compileStepRHS(binOp.right, iteratorSlot); // Compile RHS - - String op = binOp.op; - if ("+=".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ADD_INT)); } - else if ("-=".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.SUB_INT)); } - else if ("*=".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.MUL_INT)); } - else if ("/=".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.DIV_INT)); } - else { DebugSystem.warn("BYTECODE_STEP", "Unhandled compound assignment in step: " + op); } - } - } - // --- It's a "SIMPLE" step (by 2, by steps, by *2, by *2 + 1, by *+2) --- - else { - boolean isMultDiv = isMultDivStep(stepExpr); - - // Multiplicative/Divisive step ("*2", "/2", "*2 + 1", "*+2") - // The result of this expression *replaces* i. - if (isMultDiv) { - compileStepRHS(stepExpr, iteratorSlot); - } - // Additive/Subtractive step ("2", "steps", "+1", "-1") - // This expression is *added* to i. - else { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); // Load 'i' - compileStepRHS(stepExpr, iteratorSlot); // Compile the step value/expr - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ADD_INT)); // i + (result of expr) - } - } - - // --- END MODIFIED STEP LOGIC --- - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, iteratorSlot)); - - // Condition Check (same) - placeLabel(loopContinueCheck); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, endSlot)); code.add(new BytecodeInstruction(isLikelyCountdown ? BytecodeInstruction.Opcode.CMP_GE_INT : BytecodeInstruction.Opcode.CMP_LE_INT)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.JMP_IF_TRUE, loopStart)); - placeLabel(loopEnd); - } - } -// Fix the step calculation logic -private void compileStepRHS(ExprNode expr, int iteratorSlot) { - if (expr instanceof BinaryOpNode) { - BinaryOpNode binOp = (BinaryOpNode) expr; - - // Handle assignment operations in steps (e.g., "by i = i + 1") - // Note: This logic seems to be from your existing code for "by i = ..." - if (binOp.op.equals("=") || binOp.op.endsWith("=")) { - compileStepRHS(binOp.right, iteratorSlot); - return; - } - - // Standard binary operation (e.g., "by i * 2 + 1") - compileStepRHS(binOp.left, iteratorSlot); - compileStepRHS(binOp.right, iteratorSlot); - - String op = binOp.op; - if ("+".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ADD_INT)); } - else if ("-".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.SUB_INT)); } - else if ("*".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.MUL_INT)); } - else if ("/".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.DIV_INT)); } - else if ("%".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.MOD_INT)); } - return; - } - - if (expr instanceof UnaryNode) { - compileStepRHS(((UnaryNode)expr).operand, iteratorSlot); - if ("-".equals(((UnaryNode)expr).op)) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.NEG_INT)); - } - return; - } - - // --- NEW LOGIC FOR HANDLING STEP NAMES --- - - if (expr.name != null) { - String name = expr.name.trim(); - - // CASE 1: It's an operator string (e.g., "*2", "/-1", "*num", "/steps") - if (name.startsWith("*") || name.startsWith("/")) { - char op = name.charAt(0); - String operandName = name.substring(1).trim(); - - if (operandName.isEmpty()) { - DebugSystem.error("BYTECODE_STEP", "Multiplicative step operator '" + op + "' has no operand. Defaulting to 1."); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, 1)); - } else { - // Load i first for multiplicative steps - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, iteratorSlot)); - - // Now parse the operand (which could be a literal OR a variable) - Integer operandSlot = variableSlots.get(operandName); - if (operandSlot != null) { - // It's a variable (e.g., "*num") - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, operandSlot)); - } else { - // Try to parse as a literal (e.g., "*2") - try { - int value = Integer.parseInt(operandName); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, value)); - } catch (NumberFormatException e2) { - DebugSystem.error("BYTECODE_STEP", "Step operand '" + operandName + "' is not a known variable or an integer literal. Defaulting to 1."); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, 1)); - } - } - } - - // Add the operation - if (op == '*') { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.MUL_INT)); - } else { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.DIV_INT)); - } - return; - } - - // CASE 2: It's a simple variable (e.g., "i", "num", "steps") - Integer slot = variableSlots.get(name); - if (slot != null) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, slot)); - return; - } - - // CASE 3: It's a simple literal number (e.g., "2", "-1") - try { - int value = Integer.parseInt(name); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, value)); - return; - } catch (NumberFormatException e) { - // Not a simple number, and not an operator string we handled - } - - // CASE 4: Fallback - DebugSystem.warn("BYTECODE_STEP", "Unhandled step expression name: " + name + ". Defaulting to 1."); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, 1)); - return; - } - // --- END NEW LOGIC --- - - - if (expr.value != null) { - compileExpression(expr); - return; - } - - // Fallback: push 1 as default step - DebugSystem.warn("BYTECODE_STEP", "Unhandled step expression, defaulting to 1"); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, 1)); -} - - - private void compileMethodCall(MethodCallNode call) { - for (ExprNode arg : call.arguments) { compileExpression(arg); } - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CALL, call.qualifiedName)); - } - - private void compileReturnSlotAssignment(ReturnSlotAssignmentNode assignment) { - // Compile method call arguments - for (ExprNode arg : assignment.methodCall.arguments) { - compileExpression(arg); - } - - int numSlotsToReceive = assignment.variableNames.size(); - String methodName = assignment.methodCall.qualifiedName; - Object[] callOperand = new Object[] { methodName, numSlotsToReceive }; - - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CALL_SLOTS, callOperand)); - - // Store returned values to target variables - for (int i = numSlotsToReceive - 1; i >= 0; i--) { - String varName = assignment.variableNames.get(i); - int slot = getOrAllocateVariableSlot(varName); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, slot)); - } - - DebugSystem.debug("BYTECODE", "Compiled ReturnSlotAssignment for " + numSlotsToReceive + " slots from " + methodName); -} - - private void compileInput(InputNode input) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.READ_INPUT, input.targetType)); int slot = getOrAllocateVariableSlot(input.variableName); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.STORE_LOCAL, slot)); - DebugSystem.debug("BYTECODE", "Compiled InputNode for " + input.variableName + " (type: "+input.targetType+")"); - } - - private void compileExpression(ExprNode expr) { - if (expr == null) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_NULL)); return; } - if (expr instanceof UnaryNode) { compileUnary((UnaryNode) expr); } - else if (expr instanceof BinaryOpNode) { compileBinaryOperation((BinaryOpNode) expr); } - else if (expr instanceof ArrayNode) { compileArrayLiteral((ArrayNode) expr); } - else if (expr instanceof IndexAccessNode) { compileArrayAccess((IndexAccessNode) expr); } - else if (expr instanceof MethodCallNode) { compileMethodCall((MethodCallNode) expr); } - else if (expr instanceof TypeCastNode) { compileTypeCast((TypeCastNode) expr); } - else if (expr.name != null) { - Integer slot = variableSlots.get(expr.name); - if (slot != null) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_LOCAL, slot)); - } else { - DebugSystem.warn("BYTECODE", "Loading unknown name potentially as field: " + expr.name); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LOAD_FIELD, expr.name)); - } - } - else if (expr.value != null) { if (expr.value instanceof Integer) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, expr.value)); } else if (expr.value instanceof Float) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_FLOAT, expr.value)); } else if (expr.value instanceof String) { String str = (String) expr.value; if (str.length() >= 2 && str.startsWith("\"") && str.endsWith("\"")) { str = str.substring(1, str.length() - 1); } code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_STRING, str)); } else if (expr.value instanceof Boolean) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_BOOL, expr.value)); } else { DebugSystem.warn("BYTECODE", "Unhandled literal type: " + expr.value.getClass().getName()); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_NULL)); } } - else { DebugSystem.warn("BYTECODE", "Unhandled expression type: " + expr.getClass().getSimpleName()); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_NULL)); } -} - - private void compileUnary(UnaryNode unary) { - compileExpression(unary.operand); - switch (unary.op) { - case "-": code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.NEG_INT)); break; - case "+": break; // Unary plus is a no-op - default: DebugSystem.warn("BYTECODE", "Unhandled unary operator: " + unary.op); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.POP)); - } - } - - private void compileTypeCast(TypeCastNode cast) { - compileExpression(cast.expression); DebugSystem.warn("BYTECODE", "CAST instruction bytecode generation not implemented."); - } - - private void compileArrayAccess(IndexAccessNode access) { - DebugSystem.debug("BYTECODE_ARRAY", "Compiling array access: " + access.array + "[" + access.index + "]"); - compileExpression(access.array); - compileExpression(access.index); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ARRAY_LOAD)); -} - -private void compileArrayLiteral(ArrayNode literal) { - int size = literal.elements.size(); - DebugSystem.debug("BYTECODE_ARRAY", "Compiling array literal with " + size + " elements"); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, size)); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ARRAY_NEW)); - for (int i = 0; i < size; i++) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.DUP)); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_INT, i)); - compileExpression(literal.elements.get(i)); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ARRAY_STORE)); - } -} - - private void compileBinaryOperation(BinaryOpNode binOp) { - String op = binOp.op; - - if ("+".equals(op)) { - compileExpression(binOp.left); - boolean leftIsString = expressionMightBeString(binOp.left); - - compileExpression(binOp.right); - boolean rightIsString = expressionMightBeString(binOp.right); - - if (leftIsString && rightIsString) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CONCAT_STRING)); - } else if (leftIsString && !rightIsString) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.INT_TO_STRING)); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CONCAT_STRING)); - } else if (!leftIsString && rightIsString) { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.SWAP)); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.INT_TO_STRING)); - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CONCAT_STRING)); - } else { - code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.ADD_INT)); - } - return; - } - - compileExpression(binOp.left); - compileExpression(binOp.right); - - if ("-".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.SUB_INT)); } - else if ("*".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.MUL_INT)); } - else if ("/".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.DIV_INT)); } - else if ("%".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.MOD_INT)); } - else if ("==".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_EQ_INT)); } - else if ("!=".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_NE_INT)); } - else if ("<".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_LT_INT)); } - else if ("<=".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_LE_INT)); } - else if (">".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_GT_INT)); } - else if (">=".equals(op)) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.CMP_GE_INT)); } - else { DebugSystem.warn("BYTECODE", "Unhandled binary operator: " + op); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.POP)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.POP)); code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.PUSH_NULL)); } -} - - - private boolean expressionMightBeString(ExprNode expr) { - if (expr == null) return false; - if (expr.value instanceof String) return true; - if (expr instanceof BinaryOpNode && "+".equals(((BinaryOpNode)expr).op)) return true; - if (expr instanceof MethodCallNode) return true; - if (expr instanceof TypeCastNode && "string".equals(((TypeCastNode)expr).targetType)) return true; - - // Handle variable names - if (expr.name != null) { - String name = expr.name; - System.out.println("DEBUG STRING_CHECK: Checking if '" + name + "' might be string"); - - if (name.equals("name") || name.equals("op") || name.equals("operation") || - name.equals("formula") || name.equals("targetType") || - name.contains("str") || name.contains("text") || name.contains("msg") || - name.contains("label") || name.contains("type") || name.contains("Type") || - name.contains("input") || name.contains("Output")) { - System.out.println("DEBUG STRING_CHECK: '" + name + "' -> TRUE"); - return true; - } else { - System.out.println("DEBUG STRING_CHECK: '" + name + "' -> FALSE"); - } - } - - return false; -} - - - private int allocateVariableSlot(String name) { - if (variableSlots.containsKey(name)) { DebugSystem.debug("BYTECODE_VARS", "Variable '" + name + "' is being re-allocated (shadowing or temp slot)."); } - int slot = nextSlot++; variableSlots.put(name, slot); return slot; - } - - private int getExistingVariableSlot(String name) { Integer slot = variableSlots.get(name); if (slot == null) { throw new IllegalStateException("Attempted to get slot for unallocated variable/param: " + name); } return slot; } - private int getOrAllocateVariableSlot(String name) { if (!variableSlots.containsKey(name)) { return allocateVariableSlot(name); } return variableSlots.get(name); } - private String generateLabel(String prefix) { return prefix + "_" + (labelCounter++); } - private void placeLabel(String label) { code.add(new BytecodeInstruction(BytecodeInstruction.Opcode.LABEL, label)); } - -} // End of BytecodeCompiler class \ No newline at end of file From 0333094fe8d1acc81738bb16bb4aa0604a1fe15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:56:31 +0800 Subject: [PATCH 08/54] Delete src/main/java/cod/compiler/RegisterManager.java --- .../java/cod/compiler/RegisterManager.java | 529 ------------------ 1 file changed, 529 deletions(-) delete mode 100644 src/main/java/cod/compiler/RegisterManager.java diff --git a/src/main/java/cod/compiler/RegisterManager.java b/src/main/java/cod/compiler/RegisterManager.java deleted file mode 100644 index aab84596..00000000 --- a/src/main/java/cod/compiler/RegisterManager.java +++ /dev/null @@ -1,529 +0,0 @@ -package cod.compiler; - -import static cod.compiler.MTOTRegistry.CPUProfile.*; -import static cod.compiler.MTOTRegistry.AArch64Registers.*; -import static cod.compiler.MTOTRegistry.*; -import cod.debug.DebugSystem; -import java.util.*; - -public class RegisterManager { - private final RegisterAllocator registerAllocator; - private final RegisterSpiller registerSpiller; - private final RegisterFile registerFile; // Store reference - - public RegisterManager(MTOTNativeCompiler compiler) { - // --- MODIFIED: Pass registerFile directly --- - this.registerFile = compiler.cpuProfile.registerFile; - // --- END MODIFIED --- - this.registerSpiller = new RegisterSpiller(compiler); - this.registerAllocator = new RegisterAllocator(this.registerFile, registerSpiller); - } - - public RegisterAllocator getAllocator() { - return registerAllocator; - } - - public RegisterSpiller getSpiller() { - return registerSpiller; - } - - public void reset() { - registerAllocator.reset(); - registerSpiller.reset(); - } - -public class RegisterAllocator { - private final RegisterFile registerFile; - private final Stack availableRegisters = new Stack(); - // --- MODIFIED: Use LinkedHashSet for predictable iteration --- - final LinkedHashSet usedRegisters = new LinkedHashSet(); - // --- END MODIFIED --- - private final RegisterSpiller spiller; - - RegisterAllocator(RegisterFile registerFile, RegisterSpiller spiller) { - this.registerFile = registerFile; - this.spiller = spiller; - reset(); - } - - public Set getUsedRegisters() { - return new LinkedHashSet(usedRegisters); // Return a copy - } - - public void reset() { - availableRegisters.clear(); - usedRegisters.clear(); - List gp = new ArrayList(registerFile.generalPurpose); - Collections.reverse(gp); // Prefer higher numbered regs first - availableRegisters.addAll(gp); - if (spiller != null) spiller.reset(); - DebugSystem.debug("MTOT_REG", "Allocator reset. Available: " + availableRegisters.size()); - } - - public String allocateRegister() { - return allocateRegister(Collections.emptySet()); - } - - public String allocateRegister(Set avoidSpilling) { - if (availableRegisters.isEmpty()) { - DebugSystem.warn("MTOT_REG", "Out of registers! Requesting spill... Used: " + usedRegisters + ". Avoid: " + avoidSpilling); - if (spiller == null) { - throw new RuntimeException("Out of registers and no spiller configured!"); - } - // --- MODIFICATION: Pass current used registers to spiller --- - String freedRegister = spiller.spillRegister(new LinkedHashSet<>(usedRegisters), avoidSpilling); - // --- END MODIFICATION --- - - if (freedRegister == null || !usedRegisters.contains(freedRegister)) { - // Spiller might return null if it decides not to spill (e.g., only avoided regs left) - // Or, if usedRegisters was somehow modified concurrently (less likely here) - // Let's try to grab *any* available register again just in case spiller logic changes - if (!availableRegisters.isEmpty()) { - DebugSystem.warn("MTOT_REG", "Spiller didn't free a used register as expected, but one became available. Using that."); - // Proceed to pop from availableRegisters below - } else if (freedRegister != null && !usedRegisters.contains(freedRegister)) { - // Spiller returned something, but it wasn't marked as used? State inconsistency. - DebugSystem.error("MTOT_REG", "Spiller returned register " + freedRegister + " which was not in the used set! State inconsistent. Used: " + usedRegisters); - availableRegisters.push(freedRegister); // Put it back, maybe it helps - // Attempt allocation again below, might throw - } else { // freedRegister is null - throw new RuntimeException("Spiller failed to provide a register to spill (returned null)! Used: " + usedRegisters + ", Avoid: " + avoidSpilling); - } - } else { - // Successfully spilled, remove from used and add to available - usedRegisters.remove(freedRegister); - if (!availableRegisters.contains(freedRegister)) { // Avoid duplicates - availableRegisters.push(freedRegister); - } - DebugSystem.debug("MTOT_REG", "Spiller successfully freed register: " + freedRegister + ". Re-allocating."); - } - - // Check again if a register is available now - if (availableRegisters.isEmpty()) { - throw new RuntimeException("Allocation failed: No registers available even after spill attempt! Used: " + usedRegisters + ", Avoid: " + avoidSpilling); - } - } - - String reg = availableRegisters.pop(); - usedRegisters.add(reg); // Add maintains insertion order in LinkedHashSet - if (spiller != null) spiller.trackRegisterUsage(reg); // Let spiller know it's used now - DebugSystem.debug("MTOT_REG", "Allocated register: " + reg + ". Used: " + usedRegisters + ". Available: " + availableRegisters.size()); - return reg; - } - - public void freeRegister(String register) { - if (register == null) return; - - // Check if it's actually marked as used - if (usedRegisters.contains(register)) { - usedRegisters.remove(register); // Remove maintains order for others - if (registerFile.generalPurpose.contains(register)) { - // Only push back GP registers to the available pool - if (!availableRegisters.contains(register)) { // Avoid duplicates - availableRegisters.push(register); - } - if (spiller != null) spiller.untrackRegisterUsage(register); // Notify spiller it's free - DebugSystem.debug("MTOT_REG", "Freed register: " + register + ". Used: " + usedRegisters + ". Available: " + availableRegisters.size()); - } else { - // If it's not GP (e.g., arg reg, FP, SP), just removing it from used is enough. - DebugSystem.debug("MTOT_REG", "Unmarked non-GP register as used: " + register + ". Used: " + usedRegisters); - } - } - // --- MODIFICATION: Handle freeing registers not marked used (e.g., after call) --- - else if (registerFile.generalPurpose.contains(register)) { - // If it's GP but wasn't marked used, still ensure it's available - if (!availableRegisters.contains(register)) { - availableRegisters.push(register); - DebugSystem.debug("MTOT_REG", "Ensured non-used GP register is available: " + register); - } - if (spiller != null) spiller.untrackRegisterUsage(register); // Ensure spiller knows too - } - // --- END MODIFICATION --- - else if (!registerFile.argumentRegisters.contains(register) && - !register.equals(registerFile.stackPointer) && - !register.equals(registerFile.framePointer)) { - // Warn only for truly unknown registers - DebugSystem.warn("MTOT_REG", "Attempted to free unknown/invalid register: " + register); - } - } - - - public void markRegisterUsed(String register) { - if (register == null) return; - - // Check if it's a register we track (GP, Arg, SP, FP) - if (registerFile.generalPurpose.contains(register) || - registerFile.argumentRegisters.contains(register) || - register.equals(registerFile.stackPointer) || - register.equals(registerFile.framePointer) || - register.equals(AArch64Registers.x19)) { // Include 'this' explicitly if needed - - boolean wasAvailable = availableRegisters.remove(register); - boolean added = usedRegisters.add(register); // Add or update order in LinkedHashSet - - if (added || wasAvailable) { // If it was newly added or just moved from available - if (spiller != null && registerFile.generalPurpose.contains(register)) { - spiller.trackRegisterUsage(register); // Track its usage for LRU - } - DebugSystem.debug("MTOT_REG", "Marked register as used: " + register + ". Used: " + usedRegisters); - } - } else { - DebugSystem.warn("MTOT_REG", "Attempted to mark unknown/invalid register as used: " + register); - } - } -} - - -// ======================================================= -// === RegisterSpiller (Hybrid "Future Cost") === -// ======================================================= -public class RegisterSpiller { - private final MTOTNativeCompiler compiler; - private final RegisterFile registerFile; - private final Map spillSlots = new HashMap<>(); // Register -> Stack Offset - private final LinkedHashSet usageOrder = new LinkedHashSet<>(); // LRU (first) to MRU (last) - private int nextSpillOffset = -8; - private int totalSpillSize = 0; - private final Map slotToRegisterMap = new HashMap<>(); // SlotIndex -> Register - // --- NEW: Track loop depth --- - private final Map registerLoopDepth = new HashMap<>(); // Register -> Loop depth at definition - // --- END NEW --- - private final Set writtenRegistersInCurrentMethod = new HashSet<>(); - - public RegisterSpiller(MTOTNativeCompiler compiler) { - this.compiler = compiler; - this.registerFile = compiler.cpuProfile.registerFile; - } - - // --- NEW: Method to update loop depth for a register --- - public void updateRegisterDefinitionDepth(String register, int depth) { - if (register != null && registerFile.generalPurpose.contains(register)) { - registerLoopDepth.put(register, depth); - // DebugSystem.debug("SPILL_COST", "Updated loop depth for " + register + " to " + depth); - } - } - // --- END NEW --- - - // --- REVISED: spillRegister using "Future Cost" heuristic --- - public String spillRegister(LinkedHashSet currentlyUsedRegisters, Set avoidSpilling) { - if (currentlyUsedRegisters.isEmpty()) { - DebugSystem.error("SPILL", "Spill requested but no registers are marked as used!"); - return null; - } - - String bestVictim = null; - double bestScore = -1.0; // Higher score is better (spill this one) - - String fallbackVictim = null; // LRU overall - double fallbackScore = -1.0; - - List bytecode = compiler.getCurrentMethodBytecode(); // Get current method's bytecode - int currentPc = compiler.getCurrentPc(); // Get current instruction index - - // Iterate through usageOrder (LRU first) to find candidates - for (String reg : usageOrder) { - if (!currentlyUsedRegisters.contains(reg)) continue; // Only consider registers currently holding a needed value - - int nextUse = estimateNextUseDistance(reg, currentPc, bytecode); - int cost = estimateSpillCost(reg); - - // Score: Maximize nextUse distance, minimize cost (loop depth) - // Higher score means it's used further away OR less costly to reload - double score = (double) nextUse / (cost + 0.001); // Add epsilon to avoid div by zero - - // Track the absolute LRU candidate as fallback - if (fallbackVictim == null) { - fallbackVictim = reg; - fallbackScore = score; - } - - // If this register is explicitly requested to be avoided, skip primary selection - if (avoidSpilling != null && avoidSpilling.contains(reg)) { - DebugSystem.debug("SPILL", "Skipping " + reg + " (in avoid set). Score: " + score); - continue; - } - - // Is this the best candidate *so far* that we're allowed to pick? - if (bestVictim == null || score > bestScore) { - bestScore = score; - bestVictim = reg; - DebugSystem.debug("SPILL", "New best candidate: " + reg + " (Score: " + score + ", NextUse: " + nextUse + ", Cost: " + cost + ")"); - } else { - DebugSystem.debug("SPILL", "Considering " + reg + " (Score: " + score + ", NextUse: " + nextUse + ", Cost: " + cost + ") - Not better than " + bestVictim); - } - } - - // If we didn't find any suitable victim outside the avoid set - if (bestVictim == null) { - if (fallbackVictim != null) { - DebugSystem.warn("SPILL", "Forced to spill fallback LRU victim " + fallbackVictim + " (Score: " + fallbackScore + ") because best options were in avoid set."); - bestVictim = fallbackVictim; // Use the absolute LRU we tracked - } else { - DebugSystem.error("SPILL", "Cannot determine any spill victim! Used: " + currentlyUsedRegisters + ", UsageOrder: " + usageOrder); - return null; // Should not happen - } - } else { - DebugSystem.debug("SPILL", "Selected final victim " + bestVictim + " (Score: " + bestScore + ")"); - } - - forceSpill(bestVictim); - return bestVictim; - } - // --- END REVISED --- - - // --- NEW: Helper - Estimate next use distance (simplified) --- - private int estimateNextUseDistance(String register, int currentPc, List bytecode) { - if (bytecode == null) return Integer.MAX_VALUE; // Safety check - - Integer slotIndex = getSlotIndexForRegister(register); - if (slotIndex == null) { - // If we don't know which variable this register holds (e.g., temporary), - // assume it might be needed soon (give it a low distance -> high spill priority if cost is equal) - return 1; - } - - int lookaheadLimit = currentPc + 50; // Limit scan distance - for (int i = currentPc + 1; i < bytecode.size() && i < lookaheadLimit; i++) { - BytecodeInstruction instr = bytecode.get(i); - // Check if this instruction READS the slot associated with our register - if (readsSlotIndex(instr, slotIndex)) { - return i - currentPc; // Return distance - } - // Stop scan at basic block boundaries (jumps, calls, returns, labels) - if (isBasicBlockEnd(instr)) { - break; - } - } - return Integer.MAX_VALUE; // Not found within lookahead or basic block - } - - // Helper to find the slot index currently held by a register - private Integer getSlotIndexForRegister(String register) { - for (Map.Entry entry : slotToRegisterMap.entrySet()) { - if (register.equals(entry.getValue())) { - return entry.getKey(); - } - } - return null; - } - - // Helper to check if an instruction is likely to read a specific local slot - private boolean readsSlotIndex(BytecodeInstruction instr, int slotIndex) { - // This is a heuristic! More accurate analysis would need stack simulation. - switch (instr.opcode) { - case LOAD_LOCAL: - // LOAD_LOCAL *defines* a value, it doesn't read the *previous* value of that slot. - // However, if the instruction *itself* is loading our target slot, - // it means the value *currently* in the register will be overwritten. - // We consider this a "use" in the sense that the current register value is needed *before* this instruction. - return instr.operand instanceof Integer && ((Integer) instr.operand).intValue() == slotIndex; - - // Instructions that read 1 value (potentially from our slot if it's on top) - case POP: - case STORE_LOCAL: // Reads value to store - case STORE_FIELD: - case STORE_SLOT: - case PRINT: - case NEG_INT: - case INT_TO_STRING: - case JMP_IF_TRUE: - case JMP_IF_FALSE: - // Approximation: Assume it might read our slot if it reads the top of the stack. - // We can't know for sure without stack tracking. For simplicity, return false. - // A more complex check could see if LOAD_LOCAL slotIndex immediately preceded this. - return false; - - // Instructions that read 2 values - case ADD_INT: case SUB_INT: case MUL_INT: case DIV_INT: case MOD_INT: - case CMP_EQ_INT: case CMP_NE_INT: case CMP_LT_INT: case CMP_LE_INT: case CMP_GT_INT: case CMP_GE_INT: - case CONCAT_STRING: - case ARRAY_LOAD: // Reads array ref and index - case ARRAY_STORE: // Reads array ref, index, and value (reads 3, but simplifies logic) - // Approximation: Assume it might read our slot if it reads top 2 stack items. Return false. - return false; - - // Reads arguments based on arg count - complex - case CALL: - case CALL_SLOTS: - return false; // Too complex for simple lookahead - - default: - return false; - } - } - - // Helper to identify instructions ending a basic block - private boolean isBasicBlockEnd(BytecodeInstruction instr) { - switch (instr.opcode) { - case JMP: - case JMP_IF_TRUE: - case JMP_IF_FALSE: - case RET: - case CALL: - case CALL_SLOTS: - case LABEL: // Start of a new block - return true; - default: - return false; - } - } - // --- END NEW --- - - // --- NEW: Helper - Estimate spill cost --- - private int estimateSpillCost(String register) { - int depth = registerLoopDepth.getOrDefault(register, 0); - // Heavily penalize spilling registers defined inside loops - // Cost = 1 (base) + depth^2 * 10 (example weighting) - return 1 + (depth * depth * 10); - } - // --- END NEW --- - - - public void mapSlotToRegister(int slotIndex, String register) { - slotToRegisterMap.put(slotIndex, register); - DebugSystem.debug("SPILL_MAP", "Mapped slot " + slotIndex + " -> register " + register); - } - - public int getSpillOffsetForSlotIndex(int slotIndex) { - String register = slotToRegisterMap.get(slotIndex); - if (register == null) { - DebugSystem.debug("SPILL_MAP", "No register mapped for slot " + slotIndex + ", cannot get spill offset."); - return Integer.MIN_VALUE; - } - Integer offset = spillSlots.get(register); - if (offset == null) { - DebugSystem.debug("SPILL_MAP", "Register " + register + " (for slot "+slotIndex+") has no spill slot assigned."); - return Integer.MIN_VALUE; - } - return offset.intValue(); - } - - - public void forceSpill(String register) { - if (register == null || !registerFile.generalPurpose.contains(register)) { - DebugSystem.debug("SPILL", "Attempted to force spill non-GP register: " + register + " - Skipping."); - return; // Only spill general-purpose registers - } - int offset = getOrCreateSpillSlot(register); - DebugSystem.debug("SPILL", "Force spilling register " + register + " to stack offset [fp" + offset + "]"); - compiler.generateSpillCode(register, offset); - usageOrder.remove(register); // Remove from usage tracking as its value is now safely on stack - // REMOVED: registersOnStack.add(register); - } - - - // --- MAJOR REVISION (Kept from previous version): Always load if spill slot exists --- - public void fillRegister(String register) { - if (register == null || !registerFile.generalPurpose.contains(register)) { - // Don't attempt to fill non-GP registers (like args, sp, fp) - return; - } - - Integer offset = spillSlots.get(register); - // If a spill slot *exists* for this register, we MUST reload. - if (offset != null) { - DebugSystem.debug("SPILL", "Filling register " + register + " from stack offset [fp" + offset + "] (spill slot exists)."); - compiler.generateFillCode(register, offset.intValue()); - // REMOVED: registersOnStack.remove(register); - trackRegisterUsage(register); // Mark as recently used *after* filling - } else { - // No spill slot exists. Assume the register holds a valid value - // OR this is its first use and it will be written to shortly. - // We still track its usage if it was potentially used without spilling. - trackRegisterUsage(register); - DebugSystem.debug("SPILL", "Register " + register + " has no spill slot, assuming value is live or will be written."); - } - } - // --- END MAJOR REVISION --- - - public void trackRegisterUsage(String register) { - if (register != null && registerFile.generalPurpose.contains(register)) { - usageOrder.remove(register); // Remove if exists - usageOrder.add(register); // Add to end (MRU) - } - } - - public void untrackRegisterUsage(String register) { - if (register != null) { - usageOrder.remove(register); - // REMOVED: registersOnStack.remove(register); - } - } - - private int getOrCreateSpillSlot(String register) { - Integer offset = spillSlots.get(register); - if (offset == null) { - offset = Integer.valueOf(nextSpillOffset); - spillSlots.put(register, offset); - totalSpillSize += 8; // Assuming 64-bit registers - DebugSystem.debug("SPILL", "Allocated spill slot for " + register + " at offset [fp" + nextSpillOffset + "]. Total spill size (raw): " + totalSpillSize); - nextSpillOffset -= 8; - } - return offset.intValue(); - } - - public int getTotalSpillSize() { - // Ensure 16-byte alignment for the stack frame - return (totalSpillSize + 15) & ~15; - } - - // --- MAJOR REVISION (Kept from previous version): Update stack immediately if needed --- - public void markRegisterModified(String register) { - if (register == null || !registerFile.generalPurpose.contains(register)) { - return; // Only track modifications to GP registers we manage/spill - } - trackRegisterUsage(register); // Update LRU status - writtenRegistersInCurrentMethod.add(register); // Track that it was written in this method - - // Check if this register has a designated spill slot. - Integer offset = spillSlots.get(register); - if (offset != null) { - // If it has a spill slot, the value on the stack is now potentially stale. - // Force spill the *new* value immediately to keep the stack consistent. - DebugSystem.debug("SPILL", "Register " + register + " modified, forcing update to its spill slot [fp" + offset + "]"); - forceSpill(register); // forceSpill handles generating code and updating state - } else { - // If it doesn't have a spill slot, no need to update the stack yet. - DebugSystem.debug("SPILL", "Register " + register + " modified (no spill slot yet)."); - } - // REMOVED: registersOnStack.remove(register); // This line is now redundant - } - // --- END MAJOR REVISION --- - - - public Set getWrittenRegistersDuringCompilation() { - return new HashSet(writtenRegistersInCurrentMethod); - } - - public void reset() { - spillSlots.clear(); - usageOrder.clear(); - slotToRegisterMap.clear(); - registerLoopDepth.clear(); // <-- NEW: Clear depth map - // REMOVED: registersOnStack.clear(); - writtenRegistersInCurrentMethod.clear(); - nextSpillOffset = -8; // Will be set correctly by setBaseSpillOffset - totalSpillSize = 0; - DebugSystem.debug("SPILL", "Spiller reset."); - } - - public void setBaseSpillOffset(int baseOffset) { - // Base offset is typically the negative offset of the lowest callee-saved register stored. - // Spills start 8 bytes below that. - this.nextSpillOffset = baseOffset - 8; - DebugSystem.debug("SPILL", "Spiller base offset set relative to FP: " + baseOffset + ". Next spill slot at: [fp" + this.nextSpillOffset + "]"); - } - - // This method might still be useful if loading from a *known fixed offset* (like arguments passed on stack) - // For general spilling/filling, rely on the main fillRegister logic. - public void fillRegisterFromOffset(String register, int offset) { - if (register == null) return; - DebugSystem.debug("SPILL", "Explicitly filling register " + register + " from known stack offset [fp" + offset + "]"); - compiler.generateFillCode(register, offset); - // REMOVED: registersOnStack.remove(register); - trackRegisterUsage(register); // Mark as recently used - updateRegisterDefinitionDepth(register, compiler.getCurrentLoopDepth()); // Also update depth on explicit fill - } -} - -} \ No newline at end of file From 463e99a9cb7411fe762f6cdf8696c70acbc15777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:56:41 +0800 Subject: [PATCH 09/54] Delete src/main/java/cod/compiler/BytecodeInstruction.java --- .../cod/compiler/BytecodeInstruction.java | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 src/main/java/cod/compiler/BytecodeInstruction.java diff --git a/src/main/java/cod/compiler/BytecodeInstruction.java b/src/main/java/cod/compiler/BytecodeInstruction.java deleted file mode 100644 index d11c0f43..00000000 --- a/src/main/java/cod/compiler/BytecodeInstruction.java +++ /dev/null @@ -1,68 +0,0 @@ -package cod.compiler; - -public class BytecodeInstruction { - public enum Opcode { - PUSH_INT, - PUSH_FLOAT, - PUSH_STRING, - PUSH_BOOL, - PUSH_NULL, - POP, - DUP, - SWAP, - - ADD_INT, - SUB_INT, - MUL_INT, - DIV_INT, - MOD_INT, - NEG_INT, - - CONCAT_STRING, - INT_TO_STRING, - - CMP_EQ_INT, - CMP_NE_INT, - CMP_LT_INT, - CMP_LE_INT, - CMP_GT_INT, - CMP_GE_INT, - - JMP, - JMP_IF_TRUE, - JMP_IF_FALSE, - CALL, - CALL_SLOTS, - RET, - LABEL, - - LOAD_LOCAL, - STORE_LOCAL, - LOAD_FIELD, - STORE_FIELD, - STORE_SLOT, - - ARRAY_NEW, - ARRAY_LOAD, - ARRAY_STORE, - ARRAY_LENGTH, - - PRINT, - READ_INPUT, - RANGE_START, - RANGE_END, - RANGE_STEP -} - - public final Opcode opcode; - public final Object operand; - - public BytecodeInstruction(Opcode opcode, Object operand) { - this.opcode = opcode; - this.operand = operand; - } - - public BytecodeInstruction(Opcode opcode) { - this(opcode, null); - } -} \ No newline at end of file From a1b6ed0e2bb266bca6ed6c7abec5d617aa7309a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:56:54 +0800 Subject: [PATCH 10/54] Delete src/main/java/cod/compiler/BytecodeProgram.java --- .../java/cod/compiler/BytecodeProgram.java | 73 ------------------- 1 file changed, 73 deletions(-) delete mode 100644 src/main/java/cod/compiler/BytecodeProgram.java diff --git a/src/main/java/cod/compiler/BytecodeProgram.java b/src/main/java/cod/compiler/BytecodeProgram.java deleted file mode 100644 index f181316f..00000000 --- a/src/main/java/cod/compiler/BytecodeProgram.java +++ /dev/null @@ -1,73 +0,0 @@ -package cod.compiler; - -import java.util.*; - -public class BytecodeProgram { - private Map> methods = new HashMap<>(); - private Map nativeMethods = new HashMap<>(); // NEW: Native assembly storage - private List mainCode = new ArrayList<>(); - - public void addMethod(String name, List code) { - methods.put(name, new ArrayList<>(code)); - } - - // NEW: Add native method implementation - public void addNativeMethod(String name, String assemblyCode) { - nativeMethods.put(name, assemblyCode); - } - - public List getMethod(String name) { - return methods.get(name); - } - - public Map> getMethods() { - return methods; - } - - // NEW: Get native method implementation - public String getNativeMethod(String name) { - return nativeMethods.get(name); - } - - // --- ADDED: The missing method --- - public Map getNativeMethods() { - return nativeMethods; - } - // --- END ADDED --- - - public boolean hasNativeImplementation(String name) { - return nativeMethods.containsKey(name); - } - - public void setMainCode(List code) { - this.mainCode = new ArrayList<>(code); - } - - public List getMainCode() { - return mainCode; - } - - public void disassemble() { - System.out.println("=== MTOT Bytecode Disassembly ==="); - for (Map.Entry> entry : methods.entrySet()) { - System.out.println("\nMethod: " + entry.getKey()); - List instructions = entry.getValue(); - for (int i = 0; i < instructions.size(); i++) { - BytecodeInstruction instr = instructions.get(i); - System.out.printf( - " %04d: %-15s %s%n", - i, instr.opcode, instr.operand != null ? instr.operand : ""); - } - } - } - - // --- MODIFIED: Display native code --- - public void disassembleNative() { - // System.out.println("=== MTOT Native Code ==="); // <-- REMOVED - for (Map.Entry entry : nativeMethods.entrySet()) { - // System.out.println("\nMethod: " + entry.getKey()); // <-- REMOVED - System.out.println(entry.getValue()); - } - } - // --- END MODIFIED --- -} \ No newline at end of file From 69f8f1f3f61075c696f0b1719973f69018c14341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:57:09 +0800 Subject: [PATCH 11/54] Delete src/main/java/cod/compiler/MTOTRegistry.java --- src/main/java/cod/compiler/MTOTRegistry.java | 721 ------------------- 1 file changed, 721 deletions(-) delete mode 100644 src/main/java/cod/compiler/MTOTRegistry.java diff --git a/src/main/java/cod/compiler/MTOTRegistry.java b/src/main/java/cod/compiler/MTOTRegistry.java deleted file mode 100644 index 41423c85..00000000 --- a/src/main/java/cod/compiler/MTOTRegistry.java +++ /dev/null @@ -1,721 +0,0 @@ -package cod.compiler; - -import java.util.*; - -import static cod.compiler.MTOTRegistry.AArch64Registers.*; -import static cod.compiler.MTOTRegistry.x86_64Registers.*; - -public class MTOTRegistry { - - private static final Map profiles = new HashMap(); - - // ====================================================================== - // --- REGISTER DEFINITIONS --- - // ====================================================================== - - /** Contains all register definitions for the AArch64 architecture. */ - public static class AArch64Registers { - // Callee-saved (must be preserved by callee) - public static final String x19 = "x19", - x20 = "x20", - x21 = "x21", - x22 = "x22", - x23 = "x23", - x24 = "x24", - x25 = "x25", - x26 = "x26", - x27 = "x27", - x28 = "x28", - x29 = "x29", - x30 = "x30"; - - // Caller-saved (can be clobbered by callee) - public static final String x9 = "x9", - x10 = "x10", - x11 = "x11", - x12 = "x12", - x13 = "x13", - x14 = "x14", - x15 = "x15"; - - // Argument/Return registers (Caller-saved) - public static final String x0 = "x0", - x1 = "x1", - x2 = "x2", - x3 = "x3", - x4 = "x4", - x5 = "x5", - x6 = "x6", - x7 = "x7"; - - // Special Purpose - public static final String sp = "sp", - fp = "x29", // Frame Pointer - lr = "x30", // Link Register - zr = "xzr"; // Zero Register - - // Scratch / Intra-procedural (Caller-saved) - public static final String x16 = "x16", // (IP0) - x17 = "x17"; // (IP1) - - // Vector Registers (simplified names) - public static final String v0 = "v0", - v1 = "v1", - v2 = "v2", - v3 = "v3", - v4 = "v4", - v5 = "v5", - v6 = "v6", - v7 = "v7"; - } - - /** Contains all register definitions for the x86_64 (System V AMD64) architecture. */ - public static class x86_64Registers { - // Callee-saved (must be preserved by callee) - public static final String rbx = "rbx", - rbp = "rbp", // Frame Pointer - r12 = "r12", - r13 = "r13", - r14 = "r14", - r15 = "r15"; - - // Caller-saved (can be clobbered by callee) - public static final String rax = "rax", // Return value - rcx = "rcx", // Arg 4 - rdx = "rdx", // Arg 3 / Return value 2 - rsi = "rsi", // Arg 2 - rdi = "rdi", // Arg 1 - r8 = "r8", // Arg 5 - r9 = "r9", // Arg 6 - r10 = "r10", - r11 = "r11"; - - // Special Purpose - public static final String rsp = "rsp"; // Stack Pointer - - // Vector Registers (ymm for AVx) - public static final String ymm0 = "ymm0", - ymm1 = "ymm1", - ymm2 = "ymm2", - ymm3 = "ymm3", - ymm4 = "ymm4", - ymm5 = "ymm5", - ymm6 = "ymm6", - ymm7 = "ymm7"; - } - - // ====================================================================== - // --- INSTRUCTION PATTERN CONSTANTS --- - // ====================================================================== - - // Instruction patterns as final Strings - shared by both architectures - private static final String prologue = "prologue", - epilogue = "epilogue", - move_reg = "move_reg", - load_immediate_int = "load_immediate_int", - load_address = "load_address", - add_int = "add_int", - sub_int = "sub_int", - mul_int = "mul_int", - div_int = "div_int", - mod_int = "mod_int", - neg_int = "neg_int", - cmp_eq_int = "cmp_eq_int", - cmp_ne_int = "cmp_ne_int", - cmp_lt_int = "cmp_lt_int", - cmp_le_int = "cmp_le_int", - cmp_gt_int = "cmp_gt_int", - cmp_ge_int = "cmp_ge_int", - pop = "pop", - jmp = "jmp", - jmp_if_false = "jmp_if_false", - jmp_if_true = "jmp_if_true", - call = "call", - store_to_stack = "store_to_stack", - load_from_stack = "load_from_stack", - load_field_offset = "load_field_offset", - store_field_offset = "store_field_offset", - alloc_stack_frame = "alloc_stack_frame", - dealloc_stack_frame = "dealloc_stack_frame", - save_callee_reg_pair = "save_callee_reg_pair", - save_callee_reg_single = "save_callee_reg_single", - restore_callee_reg_pair = "restore_callee_reg_pair", - restore_callee_reg_single = "restore_callee_reg_single"; - - // ====================================================================== - // --- INSTRUCTION TEMPLATE STRINGS --- - // ====================================================================== - - // x86_64 instruction templates - public static final String x86_prologue_1 = "push " + rbp, - x86_prologue_2 = "mov " + rbp + ", " + rsp, - x86_epilogue_1 = "mov " + rsp + ", " + rbp, - x86_epilogue_2 = "pop " + rbp, - x86_epilogue_3 = "ret", - x86_move_reg = "mov {dest}, {src}", - x86_load_immediate_int = "mov {dest}, {value}", - x86_load_address = "mov {dest}, {label}", - x86_add_int_1 = "mov {dest}, {src1}", - x86_add_int_2 = "add {dest}, {src2}", - x86_sub_int_1 = "mov {dest}, {src1}", - x86_sub_int_2 = "sub {dest}, {src2}", - x86_mul_int_1 = "mov " + rax + ", {src1}", - x86_mul_int_2 = "imul {src2}", - x86_mul_int_3 = "mov {dest}, " + rax, - x86_div_int_1 = "mov " + rax + ", {src1}", - x86_div_int_2 = "cqo", - x86_div_int_3 = "idiv {src2}", - x86_div_int_4 = "mov {dest}, " + rax, - x86_mod_int_1 = "mov " + rax + ", {src1}", - x86_mod_int_2 = "cqo", - x86_mod_int_3 = "idiv {src2}", - x86_mod_int_4 = "mov {dest}, " + rdx, - x86_neg_int_1 = "mov {dest}, {src}", - x86_neg_int_2 = "neg {dest}", - x86_cmp_eq_int_1 = "cmp {src1}, {src2}", - x86_cmp_eq_int_2 = "sete al", - x86_cmp_eq_int_3 = "movzx {dest}, al", - x86_cmp_ne_int_1 = "cmp {src1}, {src2}", - x86_cmp_ne_int_2 = "setne al", - x86_cmp_ne_int_3 = "movzx {dest}, al", - x86_cmp_lt_int_1 = "cmp {src1}, {src2}", - x86_cmp_lt_int_2 = "setl al", - x86_cmp_lt_int_3 = "movzx {dest}, al", - x86_cmp_le_int_1 = "cmp {src1}, {src2}", - x86_cmp_le_int_2 = "setle al", - x86_cmp_le_int_3 = "movzx {dest}, al", - x86_cmp_gt_int_1 = "cmp {src1}, {src2}", - x86_cmp_gt_int_2 = "setg al", - x86_cmp_gt_int_3 = "movzx {dest}, al", - x86_cmp_ge_int_1 = "cmp {src1}, {src2}", - x86_cmp_ge_int_2 = "setge al", - x86_cmp_ge_int_3 = "movzx {dest}, al", - x86_jmp = "jmp {label}", - x86_jmp_if_false_1 = "test {condition}, {condition}", - x86_jmp_if_false_2 = "jz {label}", - x86_jmp_if_true_1 = "test {condition}, {condition}", - x86_jmp_if_true_2 = "jnz {label}", - x86_call = "call {name}", - x86_store_to_stack = "mov [" + rbp + " - {offset}], {src_reg}", // Note: x86 offsets from RBP are negative - x86_load_from_stack = "mov {dest_reg}, [" + rbp + " - {offset}]", - x86_load_field_offset = "mov {dest_reg}, [{base_reg} + {offset}]", - x86_store_field_offset = "mov [{base_reg} + {offset}], {src_reg}", - x86_alloc_stack_frame = "sub " + rsp + ", {size}", - x86_dealloc_stack_frame = "mov " + rsp + ", " + rbp, - x86_save_callee_reg_single = "push {reg}", - x86_restore_callee_reg_single = "pop {reg}"; - - // AArch64 instruction templates - public static final String - arm_prologue_1 = "stp " + x29 + ", " + x30 + ", [" + sp + ", #-16]!", - arm_prologue_2 = "mov " + x29 + ", " + sp, - arm_epilogue_1 = "mov " + sp + ", " + x29, - arm_epilogue_2 = "ldp " + x29 + ", " + x30 + ", [" + sp + "], #16", - arm_epilogue_3 = "ret", - arm_move_reg = "mov {dest}, {src}", - arm_load_immediate_int = "mov {dest}, #{value}", - arm_load_address_1 = "adrp {dest}, {label}", - arm_load_address_2 = "add {dest}, {dest}, :lo12:{label}", - arm_add_int = "add {dest}, {src1}, {src2}", - arm_sub_int = "sub {dest}, {src1}, {src2}", - arm_mul_int = "mul {dest}, {src1}, {src2}", - arm_div_int = "sdiv {dest}, {src1}, {src2}", - arm_mod_int_1 = "sdiv " + x16 + ", {src1}, {src2}", - arm_mod_int_2 = "mul " + x16 + ", " + x16 + ", {src2}", - arm_mod_int_3 = "sub {dest}, {src1}, " + x16, - arm_neg_int = "neg {dest}, {src}", - arm_cmp_eq_int_1 = "cmp {src1}, {src2}", - arm_cmp_eq_int_2 = "cset {dest}, eq", - arm_cmp_ne_int_1 = "cmp {src1}, {src2}", - arm_cmp_ne_int_2 = "cset {dest}, ne", - arm_cmp_lt_int_1 = "cmp {src1}, {src2}", - arm_cmp_lt_int_2 = "cset {dest}, lt", - arm_cmp_le_int_1 = "cmp {src1}, {src2}", - arm_cmp_le_int_2 = "cset {dest}, le", - arm_cmp_gt_int_1 = "cmp {src1}, {src2}", - arm_cmp_gt_int_2 = "cset {dest}, gt", - arm_cmp_ge_int_1 = "cmp {src1}, {src2}", - arm_cmp_ge_int_2 = "cset {dest}, ge", - arm_jmp = "b {label}", - arm_jmp_if_false_1 = "cmp {condition}, #0", - arm_jmp_if_false_2 = "b.eq {label}", - arm_jmp_if_true_1 = "cmp {condition}, #0", - arm_jmp_if_true_2 = "b.ne {label}", - arm_call = "bl {name}", - arm_store_to_stack = "str {src_reg}, [" + x29 + ", #{offset}]", // Note: ARM offsets from FP are negative - arm_load_from_stack = "ldr {dest_reg}, [" + x29 + ", #{offset}]", - arm_load_field_offset = "ldr {dest_reg}, [{base_reg}, #{offset}]", - arm_store_field_offset = "str {src_reg}, [{base_reg}, #{offset}]", - arm_alloc_stack_frame = "sub " + sp + ", " + sp + ", #{size}", - arm_dealloc_stack_frame = "mov " + sp + ", " + x29, - arm_save_callee_reg_pair = "stp {reg1}, {reg2}, [" + fp + ", #{offset}]", - arm_save_callee_reg_single = "str {reg1}, [" + fp + ", #{offset}]", - arm_restore_callee_reg_pair = "ldp {reg1}, {reg2}, [" + fp + ", #{offset}]", - arm_restore_callee_reg_single = "ldr {reg1}, [" + fp + ", #{offset}]"; - - // ====================================================================== - // --- INNER PROFILE CLASSES --- - // ====================================================================== - - /** Defines the assembly syntax for a specific toolchain (e.g., GAS, NASM). */ - public static class SyntaxProfile { - public final String commentMarker; - public final String textSection; - public final String dataSection; - public final String globalDirective; // e.g., "global {name}" - public final String stringDirective; // e.g., "{label}: db \"{value}\", 0" - public final String floatDirective; // e.g., "{label}: .float {value}" - - public SyntaxProfile( - String commentMarker, - String textSection, - String dataSection, - String globalDirective, - String stringDirective, - String floatDirective) { - this.commentMarker = commentMarker; - this.textSection = textSection; - this.dataSection = dataSection; - this.globalDirective = globalDirective; - this.stringDirective = stringDirective; - this.floatDirective = floatDirective; - } - } - - /** Defines a specific instruction pattern for a CPU. */ - public static class InstructionPattern { - public final String blockType; - public final List assemblyTemplate; - public final List requiredRegisters; - - public InstructionPattern( - String blockType, List assemblyTemplate, List requiredRegisters) { - this.blockType = blockType; - this.assemblyTemplate = assemblyTemplate; - this.requiredRegisters = requiredRegisters; - } - } - - /** Defines the vector capabilities of a CPU. */ - public static class VectorCapabilities { - public final int vectorSize; - public final boolean hasAVx; - public final boolean hasNEON; - public final boolean hasRVV; - - public VectorCapabilities(int vectorSize, boolean hasAVx, boolean hasNEON, boolean hasRVV) { - this.vectorSize = vectorSize; - this.hasAVx = hasAVx; - this.hasNEON = hasNEON; - this.hasRVV = hasRVV; - } - } - - /** Defines the register layout for a CPU. */ - public static class RegisterFile { - public final List generalPurpose; // Available for allocation - public final List vectorRegisters; - public final List argumentRegisters; // Used for args/return - public final String stackPointer; - public final String framePointer; - public final int registerCount; - - /** Constructor for AArch64 RegisterFile. */ - public RegisterFile(AArch64Registers regs) { - this.generalPurpose = - Collections.unmodifiableList( - new ArrayList( - Arrays.asList( - x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x9, - x10, x11, x12, x13, x14, x15))); - this.vectorRegisters = - Collections.unmodifiableList( - new ArrayList(Arrays.asList(v0, v1, v2, v3, v4, v5, v6, v7))); - this.argumentRegisters = - Collections.unmodifiableList( - new ArrayList(Arrays.asList(x0, x1, x2, x3, x4, x5, x6, x7))); - this.stackPointer = sp; - this.framePointer = fp; - this.registerCount = this.generalPurpose.size(); - } - - /** Constructor for x86_64 RegisterFile. */ - public RegisterFile() { - // General purpose allocatable = Callee-saved + Caller-saved (non-arg) - this.generalPurpose = - Collections.unmodifiableList( - new ArrayList( - Arrays.asList( - // Callee-saved - rbx, - r12, - r13, - r14, - r15, - // Caller-saved (non-arg, non-return) - r10, - r11))); - this.vectorRegisters = - Collections.unmodifiableList( - new ArrayList( - Arrays.asList(ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7))); - // Argument registers (in System V ABI order) - // --- MODIFIED: x86 arg regs are also used for return (rax, rdx) --- - this.argumentRegisters = - Collections.unmodifiableList( - new ArrayList(Arrays.asList( - rdi, // arg 0 - rsi, // arg 1 - rdx, // arg 2 (also return 1) - rcx, // arg 3 - r8, // arg 4 - r9, // arg 5 - rax // return 0 (not technically an arg reg, but convenient here) - ))); - this.stackPointer = rsp; - this.framePointer = rbp; - this.registerCount = this.generalPurpose.size(); - } - } - - /** Main class holding all profile information for a specific CPU architecture. */ - public static class CPUProfile { - public final String architecture; - public final Map patterns; - // --- MODIFICATION: Removed 'static' --- - public final RegisterFile registerFile; - // --- END MODIFICATION --- - public final VectorCapabilities vector; - public final SyntaxProfile syntax; - - public CPUProfile( - String architecture, - Map patterns, - RegisterFile registerFile, // <--- ADDED to constructor - VectorCapabilities vector, - SyntaxProfile syntax) { - this.architecture = architecture; - this.patterns = patterns; - this.registerFile = registerFile; // <--- ADDED assignment - this.vector = vector; - this.syntax = syntax; - } - - public InstructionPattern getPattern(String blockType) { - return patterns.get(blockType); - } - } - - // ====================================================================== - // --- REGISTRY INITIALIZATION --- - // ====================================================================== - - static { - List emptyList = Collections.emptyList(); - - // ====================================================================== - // x86_64 Profile (NASM syntax) - // ====================================================================== - - SyntaxProfile x86Syntax = - new SyntaxProfile( - ";", // commentMarker - "section .text", // textSection - "section .data", // dataSection - "global {name}", // globalDirective - "{label}: db \"{value}\", 0", // stringDirective - "{label}: dd __float32__({value})" // floatDirective (NASM syntax for 32-bit - // float) - ); - - Map x86Patterns = new HashMap(); - x86Patterns.put( - prologue, - new InstructionPattern( - prologue, Arrays.asList(x86_prologue_1, x86_prologue_2), emptyList)); - x86Patterns.put( - epilogue, - new InstructionPattern( - epilogue, - Arrays.asList(x86_epilogue_1, x86_epilogue_2, x86_epilogue_3), - emptyList)); - x86Patterns.put( - move_reg, new InstructionPattern(move_reg, Arrays.asList(x86_move_reg), emptyList)); - x86Patterns.put( - load_immediate_int, - new InstructionPattern( - load_immediate_int, Arrays.asList(x86_load_immediate_int), emptyList)); - x86Patterns.put( - load_address, - new InstructionPattern(load_address, Arrays.asList(x86_load_address), emptyList)); - x86Patterns.put( - add_int, - new InstructionPattern( - add_int, Arrays.asList(x86_add_int_1, x86_add_int_2), emptyList)); - x86Patterns.put( - sub_int, - new InstructionPattern( - sub_int, Arrays.asList(x86_sub_int_1, x86_sub_int_2), emptyList)); - x86Patterns.put( - mul_int, - new InstructionPattern( - mul_int, - Arrays.asList(x86_mul_int_1, x86_mul_int_2, x86_mul_int_3), - Arrays.asList(rax, rdx) // Clobbers rax, rdx - )); - x86Patterns.put( - div_int, - new InstructionPattern( - div_int, - Arrays.asList(x86_div_int_1, x86_div_int_2, x86_div_int_3, x86_div_int_4), - Arrays.asList(rax, rdx) // Clobbers rax, rdx - )); - x86Patterns.put( - mod_int, - new InstructionPattern( - mod_int, - Arrays.asList(x86_mod_int_1, x86_mod_int_2, x86_mod_int_3, x86_mod_int_4), - Arrays.asList(rax, rdx) // Clobbers rax, rdx - )); - x86Patterns.put( - neg_int, - new InstructionPattern( - neg_int, Arrays.asList(x86_neg_int_1, x86_neg_int_2), emptyList)); - x86Patterns.put( - cmp_eq_int, - new InstructionPattern( - cmp_eq_int, - Arrays.asList(x86_cmp_eq_int_1, x86_cmp_eq_int_2, x86_cmp_eq_int_3), - Arrays.asList("al") // Uses 'al' register - )); - x86Patterns.put( - cmp_ne_int, - new InstructionPattern( - cmp_ne_int, - Arrays.asList(x86_cmp_ne_int_1, x86_cmp_ne_int_2, x86_cmp_ne_int_3), - Arrays.asList("al"))); - x86Patterns.put( - cmp_lt_int, - new InstructionPattern( - cmp_lt_int, - Arrays.asList(x86_cmp_lt_int_1, x86_cmp_lt_int_2, x86_cmp_lt_int_3), - Arrays.asList("al"))); - x86Patterns.put( - cmp_le_int, - new InstructionPattern( - cmp_le_int, - Arrays.asList(x86_cmp_le_int_1, x86_cmp_le_int_2, x86_cmp_le_int_3), - Arrays.asList("al"))); - x86Patterns.put( - cmp_gt_int, - new InstructionPattern( - cmp_gt_int, - Arrays.asList(x86_cmp_gt_int_1, x86_cmp_gt_int_2, x86_cmp_gt_int_3), - Arrays.asList("al"))); - x86Patterns.put( - cmp_ge_int, - new InstructionPattern( - cmp_ge_int, - Arrays.asList(x86_cmp_ge_int_1, x86_cmp_ge_int_2, x86_cmp_ge_int_3), - Arrays.asList("al"))); - x86Patterns.put( - pop, new InstructionPattern(pop, Collections.emptyList(), emptyList)); - x86Patterns.put(jmp, new InstructionPattern(jmp, Arrays.asList(x86_jmp), emptyList)); - x86Patterns.put( - jmp_if_false, - new InstructionPattern( - jmp_if_false, - Arrays.asList(x86_jmp_if_false_1, x86_jmp_if_false_2), - emptyList)); - x86Patterns.put( - jmp_if_true, - new InstructionPattern( - jmp_if_true, - Arrays.asList(x86_jmp_if_true_1, x86_jmp_if_true_2), - emptyList)); - x86Patterns.put(call, new InstructionPattern(call, Arrays.asList(x86_call), emptyList)); - x86Patterns.put( - store_to_stack, - new InstructionPattern( - store_to_stack, Arrays.asList(x86_store_to_stack), emptyList)); - x86Patterns.put( - load_from_stack, - new InstructionPattern( - load_from_stack, Arrays.asList(x86_load_from_stack), emptyList)); - x86Patterns.put( - load_field_offset, - new InstructionPattern( - load_field_offset, Arrays.asList(x86_load_field_offset), emptyList)); - x86Patterns.put( - store_field_offset, - new InstructionPattern( - store_field_offset, Arrays.asList(x86_store_field_offset), emptyList)); - - x86Patterns.put(alloc_stack_frame, new InstructionPattern(alloc_stack_frame, Arrays.asList(x86_alloc_stack_frame), emptyList)); - x86Patterns.put(dealloc_stack_frame, new InstructionPattern(dealloc_stack_frame, Arrays.asList(x86_dealloc_stack_frame), emptyList)); - x86Patterns.put(save_callee_reg_single, new InstructionPattern(save_callee_reg_single, Arrays.asList(x86_save_callee_reg_single), emptyList)); - x86Patterns.put(restore_callee_reg_single, new InstructionPattern(restore_callee_reg_single, Arrays.asList(x86_restore_callee_reg_single), emptyList)); - x86Patterns.put(save_callee_reg_pair, new InstructionPattern(save_callee_reg_pair, Collections.emptyList(), emptyList)); - x86Patterns.put(restore_callee_reg_pair, new InstructionPattern(restore_callee_reg_pair, Collections.emptyList(), emptyList)); - - RegisterFile x86Registers = new RegisterFile(); - VectorCapabilities x86Vector = new VectorCapabilities(256, true, false, false); - - // --- MODIFIED: Pass RegisterFile to constructor --- - profiles.put( - "x86_64", - new CPUProfile("x86_64", x86Patterns, x86Registers, x86Vector, x86Syntax)); - // --- END MODIFIED --- - - // ====================================================================== - // AArch64 Profile (ARM64) - // ====================================================================== - - SyntaxProfile armSyntax = - new SyntaxProfile( - "//", // commentMarker - " .text", // textSection - " .data", // dataSection - " .global {name}", // globalDirective - "{label}: .asciz \"{value}\"", // stringDirective - "{label}: .float {value}" // floatDirective - ); - - Map armPatterns = new HashMap(); - armPatterns.put( - prologue, - new InstructionPattern( - prologue, Arrays.asList(arm_prologue_1, arm_prologue_2), emptyList)); - armPatterns.put( - epilogue, - new InstructionPattern( - epilogue, - Arrays.asList(arm_epilogue_1, arm_epilogue_2, arm_epilogue_3), - emptyList)); - armPatterns.put( - move_reg, new InstructionPattern(move_reg, Arrays.asList(arm_move_reg), emptyList)); - armPatterns.put( - load_immediate_int, - new InstructionPattern( - load_immediate_int, Arrays.asList(arm_load_immediate_int), emptyList)); - armPatterns.put( - load_address, - new InstructionPattern( - load_address, - Arrays.asList(arm_load_address_1, arm_load_address_2), - emptyList)); - armPatterns.put( - add_int, new InstructionPattern(add_int, Arrays.asList(arm_add_int), emptyList)); - armPatterns.put( - sub_int, new InstructionPattern(sub_int, Arrays.asList(arm_sub_int), emptyList)); - armPatterns.put( - mul_int, new InstructionPattern(mul_int, Arrays.asList(arm_mul_int), emptyList)); - armPatterns.put( - div_int, new InstructionPattern(div_int, Arrays.asList(arm_div_int), emptyList)); - armPatterns.put( - mod_int, - new InstructionPattern( - mod_int, - Arrays.asList(arm_mod_int_1, arm_mod_int_2, arm_mod_int_3), - Arrays.asList(x16) // Clobbers x16 - )); - armPatterns.put( - neg_int, new InstructionPattern(neg_int, Arrays.asList(arm_neg_int), emptyList)); - armPatterns.put( - cmp_eq_int, - new InstructionPattern( - cmp_eq_int, Arrays.asList(arm_cmp_eq_int_1, arm_cmp_eq_int_2), emptyList)); - armPatterns.put( - cmp_ne_int, - new InstructionPattern( - cmp_ne_int, Arrays.asList(arm_cmp_ne_int_1, arm_cmp_ne_int_2), emptyList)); - armPatterns.put( - cmp_lt_int, - new InstructionPattern( - cmp_lt_int, Arrays.asList(arm_cmp_lt_int_1, arm_cmp_lt_int_2), emptyList)); - armPatterns.put( - cmp_le_int, - new InstructionPattern( - cmp_le_int, Arrays.asList(arm_cmp_le_int_1, arm_cmp_le_int_2), emptyList)); - armPatterns.put( - cmp_gt_int, - new InstructionPattern( - cmp_gt_int, Arrays.asList(arm_cmp_gt_int_1, arm_cmp_gt_int_2), emptyList)); - armPatterns.put( - cmp_ge_int, - new InstructionPattern( - cmp_ge_int, Arrays.asList(arm_cmp_ge_int_1, arm_cmp_ge_int_2), emptyList)); - armPatterns.put( - pop, new InstructionPattern(pop, Collections.emptyList(), emptyList)); - armPatterns.put(jmp, new InstructionPattern(jmp, Arrays.asList(arm_jmp), emptyList)); - armPatterns.put( - jmp_if_false, - new InstructionPattern( - jmp_if_false, - Arrays.asList(arm_jmp_if_false_1, arm_jmp_if_false_2), - emptyList)); - armPatterns.put( - jmp_if_true, - new InstructionPattern( - jmp_if_true, - Arrays.asList(arm_jmp_if_true_1, arm_jmp_if_true_2), - emptyList)); - armPatterns.put(call, new InstructionPattern(call, Arrays.asList(arm_call), emptyList)); - armPatterns.put( - store_to_stack, - new InstructionPattern( - store_to_stack, Arrays.asList(arm_store_to_stack), emptyList)); - armPatterns.put( - load_from_stack, - new InstructionPattern( - load_from_stack, Arrays.asList(arm_load_from_stack), emptyList)); - armPatterns.put( - load_field_offset, - new InstructionPattern( - load_field_offset, Arrays.asList(arm_load_field_offset), emptyList)); - armPatterns.put( - store_field_offset, - new InstructionPattern( - store_field_offset, Arrays.asList(arm_store_field_offset), emptyList)); - - armPatterns.put(alloc_stack_frame, new InstructionPattern(alloc_stack_frame, Arrays.asList(arm_alloc_stack_frame), emptyList)); - armPatterns.put(dealloc_stack_frame, new InstructionPattern(dealloc_stack_frame, Arrays.asList(arm_dealloc_stack_frame), emptyList)); - armPatterns.put(save_callee_reg_pair, new InstructionPattern(save_callee_reg_pair, Arrays.asList(arm_save_callee_reg_pair), emptyList)); - armPatterns.put(save_callee_reg_single, new InstructionPattern(save_callee_reg_single, Arrays.asList(arm_save_callee_reg_single), emptyList)); - armPatterns.put(restore_callee_reg_pair, new InstructionPattern(restore_callee_reg_pair, Arrays.asList(arm_restore_callee_reg_pair), emptyList)); - armPatterns.put(restore_callee_reg_single, new InstructionPattern(restore_callee_reg_single, Arrays.asList(arm_restore_callee_reg_single), emptyList)); - - RegisterFile armRegisters = new RegisterFile(new AArch64Registers()); - VectorCapabilities armVector = new VectorCapabilities(128, false, true, false); - - // --- MODIFIED: Pass RegisterFile to constructor --- - profiles.put( - "aarch64", - new CPUProfile("aarch64", armPatterns, armRegisters, armVector, armSyntax)); - // --- END MODIFIED --- - } - - // ====================================================================== - // --- PUBLIC API --- - // ====================================================================== - - public static CPUProfile detectCPU() { - String arch = System.getProperty("os.arch").toLowerCase(); - if (arch.contains("x86_64") || arch.contains("amd64")) { - return profiles.get("x86_64"); - } else if (arch.contains("aarch64")) { - return profiles.get("aarch64"); - } - System.err.println( - "Warning: Unsupported architecture '" + arch + "'. Defaulting to aarch64."); - return profiles.get("aarch64"); - } - - public static CPUProfile getProfile(String architecture) { - CPUProfile profile = profiles.get(architecture); - if (profile == null) { - throw new IllegalArgumentException("Unsupported architecture: " + architecture); - } - return profile; - } -} \ No newline at end of file From 7a01e403108792ca087abd0ab3ac3d32e79f0588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:57:36 +0800 Subject: [PATCH 12/54] Delete src/main/java/cod/ast/error directory --- src/main/java/cod/ast/error/ParseError.java | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 src/main/java/cod/ast/error/ParseError.java diff --git a/src/main/java/cod/ast/error/ParseError.java b/src/main/java/cod/ast/error/ParseError.java deleted file mode 100644 index fcf61d22..00000000 --- a/src/main/java/cod/ast/error/ParseError.java +++ /dev/null @@ -1,16 +0,0 @@ -package cod.ast.error; - -public class ParseError extends RuntimeException { - private int line; - private int column; - - public ParseError(String message, int line, int column) { - super(message + " at line " + line + ":" + column); - this.line = line; - this.column = column; - } - - public ParseError(String message) { - super(message); - } -} From 6c3497de435b298e24e30cdf6613847c6b3d5251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:57:52 +0800 Subject: [PATCH 13/54] Delete src/main/java/cod/ast/NamingValidator.java --- src/main/java/cod/ast/NamingValidator.java | 66 ---------------------- 1 file changed, 66 deletions(-) delete mode 100644 src/main/java/cod/ast/NamingValidator.java diff --git a/src/main/java/cod/ast/NamingValidator.java b/src/main/java/cod/ast/NamingValidator.java deleted file mode 100644 index 24a14cf6..00000000 --- a/src/main/java/cod/ast/NamingValidator.java +++ /dev/null @@ -1,66 +0,0 @@ -package cod.ast; - -import cod.ast.error.ParseError; -import cod.ast.ManualCoderiveLexer.Token; - -public class NamingValidator { - - public static void validateClassName(String name, Token token) { - if (!isPascalCase(name)) { - throw new ParseError( - "Class name '" + name + "' must use PascalCase (start with uppercase letter)", - token.line, token.column - ); - } - } - - public static void validateMethodName(String name, Token token) { - if (!startsWithLowerCase(name)) { - throw new ParseError( - "Method name '" + name + "' must start with lowercase letter", - token.line, token.column - ); - } - } - - public static void validateVariableName(String name, Token token) { - // ONLY prevent PascalCase (class-like names) - if (isPascalCase(name)) { - throw new ParseError( - "Variable/parameter name '" + name + "' cannot use PascalCase (reserved for classes). " + - "Use camelCase, snake_case, or ALL_CAPS instead", - token.line, token.column - ); - } - // ALL_CAPS and lowercase are always allowed -} - -public static void validateParameterName(String name, Token token) { - // Same rule as variables - no PascalCase - validateVariableName(name, token); -} - - public static void validateConstantName(String name, Token token) { - if (!isAllCaps(name)) { - throw new ParseError( - "Constant name '" + name + "' must use ALL_CAPS with underscores", - token.line, token.column - ); - } - } - - public static boolean isPascalCase(String name) { - return name != null && !name.isEmpty() && - Character.isUpperCase(name.charAt(0)) && - !isAllCaps(name); - } - - public static boolean startsWithLowerCase(String name) { - return name != null && !name.isEmpty() && - Character.isLowerCase(name.charAt(0)); - } - - public static boolean isAllCaps(String name) { - return name != null && name.matches("[A-Z0-9_]+"); - } -} \ No newline at end of file From ffeaa6cef3766430c8c54e63f2ee40c07b1cc437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:58:07 +0800 Subject: [PATCH 14/54] Delete src/main/java/cod/ast/ManualCoderiveParser.java --- .../java/cod/ast/ManualCoderiveParser.java | 1156 ----------------- 1 file changed, 1156 deletions(-) delete mode 100644 src/main/java/cod/ast/ManualCoderiveParser.java diff --git a/src/main/java/cod/ast/ManualCoderiveParser.java b/src/main/java/cod/ast/ManualCoderiveParser.java deleted file mode 100644 index c0e0d94e..00000000 --- a/src/main/java/cod/ast/ManualCoderiveParser.java +++ /dev/null @@ -1,1156 +0,0 @@ -package cod.ast; - -import cod.ast.error.ParseError; -import cod.ast.nodes.*; -import java.util.ArrayList; -import java.util.List; -import cod.ast.ManualCoderiveLexer.Token; -import static cod.ast.ManualCoderiveLexer.TokenType.*; -import static cod.Constants.*; - -public class ManualCoderiveParser { - private final List tokens; - private int position = 0; - - public ManualCoderiveParser(List tokens) { - this.tokens = tokens; - } - - private void setNodePosition(ASTNode node, Token token) { - if (node != null && token != null) { - node.setSourcePosition(token.line, token.column); - } - } - - public ProgramNode parseProgram() { - ProgramNode program = ASTFactory.createProgram(); - if (match(UNIT)) { - program.unit = parseUnit(); - } else { - program.unit = ASTFactory.createUnit("default"); - } - - while (!match(Token.EOF)) { - if (isVisibilityModifier() || isSlotDeclaration()) { - program.unit.types.add(parseType()); - } else { - throw new ParseError("Expected type declaration (share/local) or EOF but found " + - getTypeName(currentToken().type) + " ('" + currentToken().text + - "') at line " + currentToken().line + ":" + currentToken().column); - } - } - return program; - } - - public StatementNode parseSingleLine() { - if (match(Token.EOF)) { - return null; - } - - StatementNode stmt = parseStatement(); - - if (!match(Token.EOF)) { - Token current = currentToken(); - throw new ParseError("Unexpected token after statement: " + - getTypeName(current.type) + " ('" + current.text + "')" + - " at line " + current.line + ":" + current.column); - } - return stmt; - } - - private UnitNode parseUnit() { - Token unitToken = currentToken(); - consume(UNIT); - String unitName = parseQualifiedName(); - UnitNode unit = ASTFactory.createUnit(unitName); - setNodePosition(unit, unitToken); - - if (match(GET)) { - unit.imports = parseGetNode(); - } - return unit; - } - - private GetNode parseGetNode() { - Token getToken = currentToken(); - consume(GET); - consume(LBRACE); - List imports = new ArrayList(); - if (!match(RBRACE)) { - imports.add(parseQualifiedName()); - while (tryConsume(COMMA)) { - imports.add(parseQualifiedName()); - } - } - consume(RBRACE); - GetNode getNode = ASTFactory.createGetNode(imports); - setNodePosition(getNode, getToken); - return getNode; - } - - private TypeNode parseType() { - Token visibilityToken = currentToken(); - String visibility = consume(isVisibilityModifier()).text; - Token typeNameToken = currentToken(); - String typeName = consume(ID).text; - - NamingValidator.validateClassName(typeName, typeNameToken); - - String extendName = null; - if (tryConsume(EXTEND)) { - extendName = parseQualifiedName(); - } - - TypeNode type = ASTFactory.createType(typeName, visibility, extendName); - setNodePosition(type, visibilityToken); - - consume(LBRACE); - while (!match(RBRACE)) { - if (isMethodDeclaration() || isSlotDeclaration()) { - MethodNode method = parseMethod(); - type.methods.add(method); - } else if (isFieldDeclaration()) { - type.fields.add(parseField()); - } else { - type.statements.add(parseStatement()); - } - } - consume(RBRACE); - return type; - } - - private MethodNode parseMethod() { - Token startToken = currentToken(); - - List returnSlots = null; - if (isSlotDeclaration()) { - returnSlots = parseSlotContractList(); - } - - boolean isBuiltin = false; - String visibility = share; - - if (tryConsume(BUILTIN)) { - isBuiltin = true; - visibility = share; - } else if (isVisibilityModifier()) { - visibility = consume().text; - } - - String methodName = consume(ID).text; - - NamingValidator.validateMethodName(methodName, startToken); - - MethodNode method = ASTFactory.createMethod(methodName, visibility, returnSlots); - method.isBuiltin = isBuiltin; - setNodePosition(method, startToken); - - consume(LPAREN); - if (!match(RPAREN)) { - method.parameters.add(parseParameter()); - while (tryConsume(COMMA)) { - method.parameters.add(parseParameter()); - } - } - consume(RPAREN); - - if (match(TILDE_ARROW)) { - consume(TILDE_ARROW); - ExprNode returnExpr = parseExpression(); - - SlotAssignmentNode returnStmt = ASTFactory.createSlotAssignment("return", returnExpr); - method.body.add(returnStmt); - } else { - consume(LBRACE); - while (!match(RBRACE)) { - method.body.add(parseStatement()); - } - consume(RBRACE); - } - - return method; - } - - private List parseSlotContractList() { - consume(TILDE_BAR); - List slots = new ArrayList(); - - boolean firstSlot = true; - boolean isNamedMode = false; - int index = 0; - - do { - String type = parseTypeReference(); - String name; - - if (firstSlot) { - if (currentToken().type == ID) { - isNamedMode = true; - name = consume(ID).text; - } else { - isNamedMode = false; - name = String.valueOf(index); - } - firstSlot = false; - } else { - if (isNamedMode) { - if (currentToken().type != ID) { - throw new ParseError("Mixed slot declaration styles not allowed. Expected name for slot of type " + type + "."); - } - name = consume(ID).text; - } else { - if (currentToken().type == ID) { - throw new ParseError("Mixed slot declaration styles not allowed. Found name '" + currentToken().text + "' in unnamed slot list."); - } - name = String.valueOf(index); - } - } - - slots.add(ASTFactory.createSlot(type, name)); - index++; - - } while (tryConsume(COMMA)); - - return slots; - } - - private FieldNode parseField() { - Token startToken = currentToken(); - String fieldType = parseTypeReference(); - String fieldName = consume(ID).text; - - if (NamingValidator.isAllCaps(fieldName)) { - NamingValidator.validateConstantName(fieldName, startToken); - } else { - NamingValidator.validateVariableName(fieldName, startToken); - } - - FieldNode field = ASTFactory.createField(fieldName, fieldType); - setNodePosition(field, startToken); - - if (tryConsume(ASSIGN)) { - field.value = parseExpression(); - } - return field; - } - - private StatementNode parseStatement() { - return parseStatement(null); - } - - private StatementNode parseStatement(Boolean inheritedStyle) { - if (match(IF)) return parseIfStatement(inheritedStyle); - if (match(FOR)) return parseForStatement(); - if (match(OUTPUT)) return parseOutputStatement(); - - if (isSlotAssignment()) return parseSlotAssignment(); - - if (isVariableDeclaration()) return parseVariableDeclaration(); - - if (isInputAssignment()) return parseInputAssignment(); - if (isReturnSlotAssignment()) return parseReturnSlotAssignment(); - if (isIndexAssignment()) return parseIndexAssignment(); - if (isSimpleAssignment()) return parseSimpleAssignment(); - - if (isMethodCallStatement()) { - return parseMethodCallStatement(); - } - - return parseExpressionStatement(); - } - - private SlotAssignmentNode parseSingleSlotAssignment() { - Token startToken = currentToken(); - - String slotName = null; - ExprNode value; - - if (peek(0).type == ID && - (peek(1).type == ID || - peek(1).type == INT_LIT || - peek(1).type == FLOAT_LIT || - peek(1).type == STRING_LIT || - peek(1).type == BOOL_LIT || - peek(1).type == LPAREN)) { - slotName = consume(ID).text; - value = parseExpression(); - } else { - value = parseExpression(); - } - - SlotAssignmentNode assignment = ASTFactory.createSlotAssignment(slotName, value); - setNodePosition(assignment, startToken); - return assignment; - } - - private StatementNode parseSlotAssignment() { - Token startToken = currentToken(); - consume(TILDE_ARROW); - - List assignments = new ArrayList(); - - assignments.add(parseSingleSlotAssignment()); - - if (match(COMMA)) { - while (tryConsume(COMMA)) { - assignments.add(parseSingleSlotAssignment()); - } - - MultipleSlotAssignmentNode multiAssign = ASTFactory.createMultipleSlotAssignment(assignments); - setNodePosition(multiAssign, startToken); - return multiAssign; - } else { - SlotAssignmentNode assignment = assignments.get(0); - setNodePosition(assignment, startToken); - return assignment; - } - } - - private StatementNode parseSimpleAssignment() { - Token startToken = currentToken(); - ExprNode target = ASTFactory.createIdentifier(consume(ID).text); - consume(ASSIGN); - ExprNode value = parseExpression(); - AssignmentNode assignment = ASTFactory.createAssignment(target, value); - setNodePosition(assignment, startToken); - return assignment; - } - - private StatementNode parseVariableDeclaration() { - Token startToken = currentToken(); - String typeName = null; - if (tryConsume(VAR)) { - typeName = "var"; - } else if (isTypeStart(currentToken())) { - typeName = parseTypeReference(); - } else { - throw new ParseError("Internal Error: Expected 'var' or type name at start of variable declaration."); - } - - Token varNameToken = currentToken(); - String varName = consume(ID).text; - - if (NamingValidator.isAllCaps(varName)) { - NamingValidator.validateConstantName(varName, varNameToken); - } else { - NamingValidator.validateVariableName(varName, varNameToken); - } - - VarNode varNode = ASTFactory.createVar(varName, null); - setNodePosition(varNode, startToken); - varNode.explicitType = typeName; - - if (tryConsume(ASSIGN)) { - varNode.value = parseExpression(); - } - return varNode; - } - - private StatementNode parseIfStatement() { - return parseIfStatement(null); - } - - private StatementNode parseIfStatement(Boolean inheritedStyle) { - Token startToken = currentToken(); - consume(IF); - ExprNode condition = parseExpression(); - IfNode rootIfNode = ASTFactory.createIf(condition); - setNodePosition(rootIfNode, startToken); - - Boolean currentStyle = inheritedStyle; - - if (match(LBRACE)) { - consume(LBRACE); - while(!match(RBRACE)) { - rootIfNode.thenBlock.statements.add(parseStatement(currentStyle)); - } - consume(RBRACE); - } else { - rootIfNode.thenBlock.statements.add(parseStatement(currentStyle)); - } - - IfNode currentNode = rootIfNode; - - while (tryConsume(ELIF)) { - if (currentStyle != null && !currentStyle) { - throw new ParseError("Cannot use 'elif' in an 'else if' style chain"); - } - currentStyle = true; - - ExprNode elifCondition = parseExpression(); - IfNode elifNode = ASTFactory.createIf(elifCondition); - - if (match(LBRACE)) { - consume(LBRACE); - while(!match(RBRACE)) { - elifNode.thenBlock.statements.add(parseStatement(currentStyle)); - } - consume(RBRACE); - } else { - elifNode.thenBlock.statements.add(parseStatement(currentStyle)); - } - - currentNode.elseBlock.statements.add(elifNode); - currentNode = elifNode; - } - - if (tryConsume(ELSE)) { - if (match(IF)) { - if (currentStyle != null && currentStyle) { - throw new ParseError("Cannot use 'else if' in an 'elif' style chain"); - } - currentStyle = false; - - currentNode.elseBlock.statements.add(parseIfStatement(currentStyle)); - } else { - if (match(LBRACE)) { - consume(LBRACE); - while(!match(RBRACE)) { - currentNode.elseBlock.statements.add(parseStatement(currentStyle)); - } - consume(RBRACE); - } else { - currentNode.elseBlock.statements.add(parseStatement(currentStyle)); - } - } - } - - return rootIfNode; - } - - private StatementNode parseForStatement() { - Token startToken = currentToken(); - consume(FOR); - String iterator = consume(ID).text; - - ExprNode by = null; - - if (tryConsume(BY)) { - if (match(MUL, DIV)) { - Token operator = consume(); - ExprNode operand = parseExpression(); - ExprNode iteratorRef = ASTFactory.createIdentifier(iterator); - by = ASTFactory.createBinaryOp(iteratorRef, operator.text, operand); - } else if (match(PLUS, MINUS)) { - Token operator = consume(); - if (peek(0).type == INT_LIT || peek(0).type == FLOAT_LIT) { - ExprNode operand = parsePrimaryExpression(); - if (operator.type == PLUS) { - by = operand; - } else { - by = ASTFactory.createUnaryOp("-", operand); - } - } else { - position--; - by = parseExpression(); - } - } else { - if (isAssignmentInByClause()) { - ExprNode target = ASTFactory.createIdentifier(consume(ID).text); - if (!target.name.equals(iterator)) { - System.err.println("[Parser Warning] Variable in 'by' assignment ("+target.name+") doesn't match iterator ("+iterator+")."); - } - Token assignOp = consume(); - ExprNode value = parseExpression(); - by = ASTFactory.createBinaryOp(target, assignOp.text, value); - } else { - by = parseExpression(); - } - } - - consume(IN); - } else { - by = null; - consume(IN); - } - - ExprNode start = parseExpression(); - consume(TO); - ExprNode end = parseExpression(); - - RangeNode range = ASTFactory.createRange(by, start, end); - ForNode forNode = ASTFactory.createFor(iterator, range); - setNodePosition(forNode, startToken); - - consume(LBRACE); - while (!match(RBRACE)) { - forNode.body.statements.add(parseStatement()); - } - consume(RBRACE); - return forNode; - } - - private StatementNode parseOutputStatement() { - Token startToken = currentToken(); - consume(OUTPUT); - OutputNode output = ASTFactory.createOutput(); - setNodePosition(output, startToken); - output.arguments.add(parseExpression()); - return output; - } - - private StatementNode parseInputAssignment() { - Token startToken = currentToken(); - String varName = consume(ID).text; - consume(ASSIGN); - consume(LPAREN); - String type = parseTypeReference(); - consume(RPAREN); - consume(INPUT); - InputNode input = ASTFactory.createInput(type, varName); - setNodePosition(input, startToken); - return input; - } - - private StatementNode parseReturnSlotAssignment() { - Token startToken = currentToken(); - List varNames = parseIdList(); - consume(ASSIGN); - List slotNames = parseReturnSlots(); - consume(COLON); - MethodCallNode methodCall = parseMethodCall(); - methodCall.slotNames = slotNames; - - if (varNames.size() != slotNames.size()) { - throw new ParseError("Number of variables (" + varNames.size() + - ") does not match number of slots (" + slotNames.size() + ")"); - } - - ReturnSlotAssignmentNode assignment = ASTFactory.createReturnSlotAssignment(varNames, methodCall); - setNodePosition(assignment, startToken); - return assignment; - } - - private StatementNode parseIndexAssignment() { - Token startToken = currentToken(); - ExprNode arrayVar = ASTFactory.createIdentifier(consume(ID).text); - IndexAccessNode indexAccess = parseIndexAccessContinuation(arrayVar); - while(match(LBRACKET)) { - indexAccess = parseIndexAccessContinuation(indexAccess); - } - consume(ASSIGN); - ExprNode value = parseExpression(); - AssignmentNode assignment = ASTFactory.createAssignment(indexAccess, value); - setNodePosition(assignment, startToken); - return assignment; - } - - private StatementNode parseMethodCallStatement() { - Token startToken = currentToken(); - if (peek(0).type == LBRACKET) { - List slotNames = parseReturnSlots(); - consume(COLON); - MethodCallNode methodCall = parseMethodCall(); - methodCall.slotNames = slotNames; - setNodePosition(methodCall, startToken); - return methodCall; - } else { - MethodCallNode methodCall = parseMethodCall(); - setNodePosition(methodCall, startToken); - return methodCall; - } - } - - private StatementNode parseExpressionStatement() { - Token startToken = currentToken(); - ExprNode expr = parseExpression(); - setNodePosition(expr, startToken); - return expr; - } - -private ExprNode parseExpression() { - if (match(ALL, ANY)) { - return parseBooleanChain(); - } - return parseComparisonExpression(); - } - - - private ExprNode parseBooleanChain() { - Token startToken = currentToken(); - Token typeToken = consume(); - boolean isAll = typeToken.type == ALL; - if (match(ID)) { - - ExprNode arrayExpr = ASTFactory.createIdentifier(consume().text); - - if (match(EQ, NEQ, GT, LT, GTE, LTE)) { - Token op = consume(); - - ExprNode right = parseAdditiveExpression(); - - List chainArgs = new ArrayList(); - chainArgs.add(right); - - EqualityChainNode chain = ASTFactory.createEqualityChain(arrayExpr, op.text, isAll, chainArgs); - setNodePosition(chain, startToken); - return chain; - } else { - throw new ParseError("Expected comparison operator after 'all/any ' but found " + - getTypeName(currentToken().type) + " ('" + currentToken().text + - "') at line " + currentToken().line + ":" + currentToken().column); - } - } else { - consume(LBRACKET); - List expressions = new ArrayList(); - - if (!match(RBRACKET)) { - expressions.add(parseExpression()); - if (!match(COMMA) && !match(RBRACKET)) { - throw new ParseError("Boolean chain requires at least two expressions or a comma after the first expression."); - } - while (tryConsume(COMMA)) { - expressions.add(parseExpression()); - } - } - consume(RBRACKET); - BooleanChainNode node = ASTFactory.createBooleanChain(isAll, expressions); - if (node != null) { - node.setSourcePosition(startToken.line, startToken.column); - } - return node; - } - } - - private ExprNode parseComparisonExpression() { - Token startToken = currentToken(); - ExprNode left = parseAdditiveExpression(); - - // --- NEW: Check for reverse equality chain (e.g., 'x == any[...]') --- - if (match(EQ, NEQ, GT, LT, GTE, LTE) && isEqualityChainReverse()) { - Token op = consume(); - return parseEqualityChain(left, op.text); - } - - if (match(EQ, NEQ, GT, LT, GTE, LTE)) { - Token op = consume(); - - if (match(ALL, ANY)) { - return parseEqualityChain(left, op.text); - } - - ExprNode right = parseAdditiveExpression(); - left = ASTFactory.createBinaryOp(left, op.text, right); - setNodePosition(left, startToken); - } - return left; - } - - private ExprNode parseEqualityChain(ExprNode left, String operator) { - Token startToken = currentToken(); - Token chainTypeToken = consume(); - boolean isAllChain = chainTypeToken.type == ALL; - - // --- UPDATED: Looking for LBRACKET instead of LPAREN --- - consume(LBRACKET); - - List chainArgs = new ArrayList(); - // --- UPDATED: Looking for RBRACKET instead of RPAREN --- - if (!match(RBRACKET)) { - chainArgs.add(parseChainArgument()); - while (tryConsume(COMMA)) { - chainArgs.add(parseChainArgument()); - } - } - // --- UPDATED: Consuming RBRACKET instead of RPAREN --- - consume(RBRACKET); - - EqualityChainNode chain = ASTFactory.createEqualityChain(left, operator, isAllChain, chainArgs); - setNodePosition(chain, startToken); - return chain; - } - - private MethodCallNode parseConditionalChainCall(MethodCallNode call) { - Token chainTypeToken = consume(); - boolean isAllChain = chainTypeToken.type == ALL; - call.chainType = isAllChain ? "all" : "any"; - - // --- UPDATED: Mandate LBRACKET and RBRACKET for chain arguments --- - consume(LBRACKET); - - List chainArgs = new ArrayList(); - if (!match(RBRACKET)) { - chainArgs.add(parseChainArgument()); - while (tryConsume(COMMA)) { - chainArgs.add(parseChainArgument()); - } - } - - // --- UPDATED: Consume RBRACKET --- - consume(RBRACKET); - - call.chainArguments = chainArgs; - return call; - } - - private ExprNode parseAdditiveExpression() { - Token startToken = currentToken(); - ExprNode left = parseMultiplicativeExpression(); - while (match(PLUS, MINUS)) { - Token op = consume(); - ExprNode right = parseMultiplicativeExpression(); - left = ASTFactory.createBinaryOp(left, op.text, right); - setNodePosition(left, startToken); - } - return left; - } - - private ExprNode parseMultiplicativeExpression() { - Token startToken = currentToken(); - ExprNode left = parseUnaryExpression(); - while (match(MUL, DIV, MOD)) { - Token op = consume(); - ExprNode right = parseUnaryExpression(); - left = ASTFactory.createBinaryOp(left, op.text, right); - setNodePosition(left, startToken); - } - return left; - } - - private ExprNode parseUnaryExpression() { - Token startToken = currentToken(); - if (match(BANG)) { - Token op = consume(); - ExprNode operand = parsePrimaryExpression(); - UnaryNode unary = ASTFactory.createUnaryOp(op.text, operand); - setNodePosition(unary, startToken); - return unary; - } - if (match(PLUS, MINUS)) { - Token op = consume(); - ExprNode operand = parsePrimaryExpression(); - UnaryNode unary = ASTFactory.createUnaryOp(op.text, operand); - setNodePosition(unary, startToken); - return unary; - } - return parsePrimaryExpression(); - } - - private ExprNode parseArrayLiteral() { - Token startToken = currentToken(); - consume(LBRACKET); - List elements = new ArrayList(); - if (!match(RBRACKET)) { - elements.add(parseExpression()); - while (tryConsume(COMMA)) { - elements.add(parseExpression()); - } - } - consume(RBRACKET); - ArrayNode array = ASTFactory.createArray(elements); - setNodePosition(array, startToken); - return array; - } - - private ExprNode parsePrimaryExpression() { - ExprNode baseExpr; - Token startToken = currentToken(); - - if (match(LBRACKET)) { - baseExpr = parseArrayLiteral(); - } else if (match(INT_LIT)) { - baseExpr = ASTFactory.createIntLiteral(Integer.parseInt(consume().text)); - setNodePosition(baseExpr, startToken); - } else if (match(FLOAT_LIT)) { - baseExpr = ASTFactory.createFloatLiteral(Float.parseFloat(consume().text)); - setNodePosition(baseExpr, startToken); - } else if (match(STRING_LIT)) { - Token stringToken = consume(); - baseExpr = ASTFactory.createStringLiteral(stringToken.text); - setNodePosition(baseExpr, stringToken); - } else if (match(BOOL_LIT)) { - baseExpr = ASTFactory.createBoolLiteral(Boolean.parseBoolean(consume().text)); - setNodePosition(baseExpr, startToken); - } else if (match(ID)) { - if (isMethodCallFollows()) { - baseExpr = parseMethodCall(); - } else { - baseExpr = ASTFactory.createIdentifier(consume().text); - setNodePosition(baseExpr, startToken); - } - } else if (match(LPAREN)) { - if (isTypeCast()) { - baseExpr = parseTypeCast(); - } else { - consume(LPAREN); - baseExpr = parseExpression(); - consume(RPAREN); - setNodePosition(baseExpr, startToken); - } - } else { - throw new ParseError("Unexpected token in primary expression: " + startToken.text + - " (" + getTypeName(startToken.type) + ")" + - " at line " + startToken.line + ":" + startToken.column); - } - - while (match(LBRACKET)) { - baseExpr = parseIndexAccessContinuation(baseExpr); - } - - return baseExpr; - } - - private MethodCallNode parseMethodCall() { - Token startToken = currentToken(); - String qualifiedNameStr = parseQualifiedName(); - String methodName = qualifiedNameStr; - if (qualifiedNameStr.contains(".")) { - methodName = qualifiedNameStr.substring(qualifiedNameStr.lastIndexOf('.') + 1); - } - MethodCallNode call = ASTFactory.createMethodCall(methodName, qualifiedNameStr); - setNodePosition(call, startToken); - - consume(LPAREN); - - if (match(ALL, ANY)) { - return parseConditionalChainCall(call); - } - - if (!match(RPAREN)) { - call.arguments.add(parseExpression()); - while (tryConsume(COMMA)) { - call.arguments.add(parseExpression()); - } - } - consume(RPAREN); - return call; - } - - private ExprNode parseChainArgument() { - if (match(BANG)) { - consume(BANG); - ExprNode arg = parsePrimaryExpression(); - UnaryNode negatedArg = ASTFactory.createUnaryOp("!", arg); - setNodePosition(negatedArg, currentToken()); - return negatedArg; - } - - return parsePrimaryExpression(); - } - - private IndexAccessNode parseIndexAccessContinuation(ExprNode arrayExpr) { - Token startToken = currentToken(); - consume(LBRACKET); - ExprNode indexExpr = parseExpression(); - consume(RBRACKET); - IndexAccessNode access = ASTFactory.createIndexAccess(arrayExpr, indexExpr); - setNodePosition(access, startToken); - return access; - } - - private ExprNode parseTypeCast() { - Token startToken = currentToken(); - consume(LPAREN); - String type = parseTypeReference(); - consume(RPAREN); - ExprNode expressionToCast = parseUnaryExpression(); - TypeCastNode cast = ASTFactory.createTypeCast(type, expressionToCast); - setNodePosition(cast, startToken); - return cast; - } - - private List parseReturnSlots() { - consume(LBRACKET); - List slots = new ArrayList(); - do { - if (match(ID)) { - slots.add(consume(ID).text); - } else if (match(INT_LIT)) { - slots.add(consume(INT_LIT).text); - } else { - throw new ParseError("Expected slot name or index, found " + currentToken().text); - } - } while (tryConsume(COMMA)); - consume(RBRACKET); - return slots; - } - - private List parseIdList() { - List ids = new ArrayList(); - ids.add(consume(ID).text); - while (tryConsume(COMMA)) { - ids.add(consume(ID).text); - } - return ids; - } - - private ParamNode parseParameter() { - Token startToken = currentToken(); - String type = parseTypeReference(); - Token paramNameToken = currentToken(); - String name = consume(ID).text; - - NamingValidator.validateParameterName(name, paramNameToken); - - ParamNode param = ASTFactory.createParam(name, type); - setNodePosition(param, startToken); - return param; - } - - private boolean isSlotDeclaration() { - try { - return tokens.get(position).type == TILDE_BAR; - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - private boolean isSlotAssignment() { - try { - if (tokens.get(position).type != TILDE_ARROW) return false; - if (position + 1 >= tokens.size()) return false; - - int nextPos = position + 1; - Token nextToken = tokens.get(nextPos); - - return nextToken.type == ID || - nextToken.type == INT_LIT || - nextToken.type == FLOAT_LIT || - nextToken.type == STRING_LIT || - nextToken.type == BOOL_LIT || - nextToken.type == LPAREN || - nextToken.type == LBRACKET || - nextToken.type == PLUS || - nextToken.type == MINUS; - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - private boolean isTypeCast() { - int p = position; try { if (tokens.get(p++).type != LPAREN) return false; if (!isTypeStart(tokens.get(p))) return false; p++; while (p < tokens.size() && tokens.get(p).type == LBRACKET) { if (p + 1 < tokens.size() && tokens.get(p + 1).type == RBRACKET) { p += 2; } else { return false; } } if (p >= tokens.size() || tokens.get(p++).type != RPAREN) return false; if (p >= tokens.size()) return false; int nt = tokens.get(p).type; return nt == LBRACKET || nt == INT_LIT || nt == FLOAT_LIT || nt == STRING_LIT || nt == BOOL_LIT || nt == ID || nt == LPAREN || nt == PLUS || nt == MINUS; } catch (IndexOutOfBoundsException e) { return false; } - } - - private boolean isMethodDeclaration() { - int p = position; - try { - if (tokens.get(p).type == TILDE_BAR) { - p++; - while(p < tokens.size() && (isTypeStart(tokens.get(p)) || tokens.get(p).type == ID || tokens.get(p).type == COMMA || tokens.get(p).type == LBRACKET || tokens.get(p).type == RBRACKET)) { - p++; - } - } - - if (tokens.get(p).type == BUILTIN || isVisibilityModifier(tokens.get(p))) { - p++; - } - - if (p >= tokens.size() || tokens.get(p).type != ID) return false; - p++; - - if (p >= tokens.size() || tokens.get(p).type != LPAREN) return false; - p++; - - int parenDepth = 1; - while (p < tokens.size() && parenDepth > 0) { - if (tokens.get(p).type == LPAREN) parenDepth++; - else if (tokens.get(p).type == RPAREN) parenDepth--; - p++; - } - - if (p >= tokens.size()) return false; - - return tokens.get(p).type == TILDE_ARROW || - tokens.get(p).type == LBRACE; - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - private boolean isFieldDeclaration() { - int p = position; try { if (!isTypeStart(tokens.get(p))) return false; p++; while (p < tokens.size() && tokens.get(p).type == LBRACKET) { if (p + 1 < tokens.size() && tokens.get(p + 1).type == RBRACKET) { p += 2; } else { return false; } } if (p >= tokens.size() || tokens.get(p).type != ID) return false; p++; return p >= tokens.size() || tokens.get(p).type != LPAREN; } catch (IndexOutOfBoundsException e) { return false; } - } - - private boolean isInputAssignment() { - int p = position; try { if (tokens.get(p++).type != ID) return false; if (tokens.get(p++).type != ASSIGN) return false; if (tokens.get(p++).type != LPAREN) return false; if (!isTypeStart(tokens.get(p))) return false; p++; while (p < tokens.size() && tokens.get(p).type == LBRACKET) { if (p + 1 < tokens.size() && tokens.get(p + 1).type == RBRACKET) { p += 2; } else { return false; } } if (p >= tokens.size() || tokens.get(p++).type != RPAREN) return false; return p < tokens.size() && tokens.get(p).type == INPUT; } catch (IndexOutOfBoundsException e) { return false; } - } - - private boolean isSimpleAssignment() { - int p = position; - try { - if (tokens.get(p).type != ID) return false; - if (p + 1 < tokens.size() && tokens.get(p + 1).type == LBRACKET) return false; - if (p + 1 >= tokens.size() || tokens.get(p + 1).type != ASSIGN) return false; - if (p + 2 < tokens.size() && tokens.get(p + 2).type == LPAREN) return false; - return true; - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - private boolean isIndexAssignment() { - int p = position; try { if (tokens.get(p++).type != ID) return false; if (p >= tokens.size() || tokens.get(p++).type != LBRACKET) return false; int bd = 1; while (p < tokens.size() && bd > 0) { if (tokens.get(p).type == LBRACKET) bd++; else if (tokens.get(p).type == RBRACKET) bd--; p++; } if (bd != 0) return false; while (p < tokens.size() && tokens.get(p).type == LBRACKET) { p++; bd = 1; while (p < tokens.size() && bd > 0) { if (tokens.get(p).type == LBRACKET) bd++; else if (tokens.get(p).type == RBRACKET) bd--; p++; } if (bd != 0) return false; } return p < tokens.size() && tokens.get(p).type == ASSIGN; } catch (IndexOutOfBoundsException e) { return false; } - } - - private boolean isMethodCallFollows() { - int p = position; - try { - if (tokens.get(p).type != ID) return false; - p++; - while(p < tokens.size() && tokens.get(p).type == DOT) { - p++; - if (p >= tokens.size() || tokens.get(p).type != ID) return false; - p++; - } - if (p >= tokens.size() || tokens.get(p).type != LPAREN) return false; - p++; - - if (p < tokens.size() && (tokens.get(p).type == ALL || tokens.get(p).type == ANY)) { - p++; - return p < tokens.size() && tokens.get(p).type == LBRACKET; - } - - return true; - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - // --- NEW: Helper for reverse equality chain --- - private boolean isEqualityChainReverse() { - int p = position; - try { - // Check for Operator - if (tokens.get(p).type != EQ && tokens.get(p).type != NEQ && - tokens.get(p).type != GT && tokens.get(p).type != LT && - tokens.get(p).type != GTE && tokens.get(p).type != LTE) return false; - p++; - - // Check for ALL/ANY followed by LBRACKET - if (tokens.get(p).type != ALL && tokens.get(p).type != ANY) return false; - p++; - - return tokens.get(p).type == LBRACKET; - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - - private boolean isReturnSlotAssignment() { - int p = position; try { if (tokens.get(p++).type != ID) return false; while (p < tokens.size() && tokens.get(p).type == COMMA) { p++; if (p >= tokens.size() || tokens.get(p++).type != ID) return false; } if (p >= tokens.size() || tokens.get(p++).type != ASSIGN) return false; if (p >= tokens.size() || tokens.get(p++).type != LBRACKET) return false; - if (p >= tokens.size()) return false; - if (tokens.get(p).type == ID || tokens.get(p).type == INT_LIT) { p++; } else { return false; } - while (p < tokens.size() && tokens.get(p).type == COMMA) { p++; if (p >= tokens.size()) return false; if (tokens.get(p).type == ID || tokens.get(p).type == INT_LIT) { p++; } else { return false; } } if (p >= tokens.size() || tokens.get(p++).type != RBRACKET) return false; return p < tokens.size() && tokens.get(p).type == COLON; } catch (IndexOutOfBoundsException e) { return false; } - } - - private boolean isVariableDeclaration() { - int p = position; try { Token first = tokens.get(p); if (first.type == VAR) { return p + 1 < tokens.size() && tokens.get(p + 1).type == ID; } else if (isTypeStart(first)) { p++; while (p < tokens.size() && tokens.get(p).type == LBRACKET) { if (p + 1 < tokens.size() && tokens.get(p + 1).type == RBRACKET) { p += 2; } else { return false; } } return p < tokens.size() && tokens.get(p).type == ID; } return false; } catch (IndexOutOfBoundsException e) { return false; } - } - - private boolean isAssignmentInByClause() { - int p = position; try { if (tokens.get(p).type != ID) return false; int nt = tokens.get(p + 1).type; return nt == ASSIGN || nt == PLUS_ASSIGN || nt == MINUS_ASSIGN || nt == MUL_ASSIGN || nt == DIV_ASSIGN; } catch (IndexOutOfBoundsException e) { return false; } - } - - private boolean isMethodCallStatement() { - int p = position; try { if (tokens.get(p).type == LBRACKET) { p++; - if (tokens.get(p).type == ID || tokens.get(p).type == INT_LIT) { p++; } else { return false; } - while(p < tokens.size() && tokens.get(p).type == COMMA) { p+=2; } if (p >= tokens.size() || tokens.get(p).type != RBRACKET) return false; p++; if (p >= tokens.size() || tokens.get(p).type != COLON) return false; p++; } if (tokens.get(p).type != ID) return false; p++; while(p < tokens.size() && tokens.get(p).type == DOT) { p++; if (p >= tokens.size() || tokens.get(p).type != ID) return false; p++; } return p < tokens.size() && tokens.get(p).type == LPAREN; } catch (IndexOutOfBoundsException e) { return false; } - } - - private String parseQualifiedName() { - StringBuilder name = new StringBuilder(); - name.append(consume(ID).text); - while (tryConsume(DOT)) { - name.append("."); - name.append(consume(ID).text); - } - return name.toString(); - } - - private String parseTypeReference() { - StringBuilder typeName = new StringBuilder(); - if (isTypeStart(currentToken())) { - typeName.append(consume().text); - } else { - Token current = currentToken(); - throw new ParseError("Expected type name (int, string, float, bool, or ID) but got " + - getTypeName(current.type) + " ('" + current.text + "')" + - " at line " + current.line + ":" + current.column); - } - while (match(LBRACKET)) { - consume(LBRACKET); - consume(RBRACKET); - typeName.append("[]"); - } - return typeName.toString(); - } - - private boolean isTypeKeyword(int type) { - return type == INT || type == STRING || - type == FLOAT || type == BOOL; - } - - private boolean isTypeStart(Token token) { - if (token == null) return false; - return isTypeKeyword(token.type) || token.type == ID; - } - - private boolean isVisibilityModifier() { - return match(SHARE, LOCAL); - } - - private boolean isVisibilityModifier(Token token) { - if (token == null) return false; - return token.type == SHARE || token.type == LOCAL; - } - - private Token currentToken() { - return (position >= tokens.size()) ? tokens.get(tokens.size() - 1) : tokens.get(position); - } - - private Token peek(int offset) { - int targetPos = position + offset; - if (targetPos >= tokens.size()) return tokens.get(tokens.size() - 1); - if (targetPos < 0) { return null; } - return tokens.get(targetPos); - } - - private boolean match(int... types) { - Token current = currentToken(); - if (current.type == Token.EOF) { - for (int type : types) { if (type == Token.EOF) return true; } - return false; - } - for (int type : types) { - if (current.type == type) return true; - } - return false; - } - - private Token consume() { - Token token = currentToken(); - if (token.type != Token.EOF) position++; - return token; - } - - private Token consume(int expectedType) { - Token token = currentToken(); - if (token.type == expectedType) { - if (token.type != Token.EOF) position++; - return token; - } - throw new ParseError("Expected " + getTypeName(expectedType) + " but found " + - getTypeName(token.type) + " ('" + token.text + "') at line " + token.line + ":" + token.column); - } - - private Token consume(boolean condition) { - if (condition) return consume(); - Token current = currentToken(); - throw new ParseError("Consumption condition not met at: " + current.text + - " (" + getTypeName(current.type) + ")" + - " at line " + current.line + ":" + current.column); - } - - private boolean tryConsume(int expectedType) { - if (match(expectedType)) { - consume(expectedType); - return true; - } - return false; - } - - private String getTypeName(int type) { - return ManualCoderiveLexer.TokenType.getName(type); - } -} \ No newline at end of file From 2a580d62451c02a81992c361c0b9c788ad82a31b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:58:18 +0800 Subject: [PATCH 15/54] Delete src/main/java/cod/ast/ManualCoderiveLexer.java --- .../java/cod/ast/ManualCoderiveLexer.java | 436 ------------------ 1 file changed, 436 deletions(-) delete mode 100644 src/main/java/cod/ast/ManualCoderiveLexer.java diff --git a/src/main/java/cod/ast/ManualCoderiveLexer.java b/src/main/java/cod/ast/ManualCoderiveLexer.java deleted file mode 100644 index 3ce3c1f4..00000000 --- a/src/main/java/cod/ast/ManualCoderiveLexer.java +++ /dev/null @@ -1,436 +0,0 @@ -package cod.ast; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static cod.Constants.*; - -public class ManualCoderiveLexer { - - public static class Token { - public final int type; - public final String text; - public final int line; - public final int column; - - public static final int EOF = -1; - - public Token(int type, String text, int line, int column) { - this.type = type; - this.text = text; - this.line = line; - this.column = column; - } - - @Override - public String toString() { - return "Token{" - + "type=" - + TokenType.getName(type) - + ", text='" - + text - + '\'' - + ", line=" - + line - + ", column=" - + column - + '}'; - } - } - - public static class TokenType { - public static final int SHARE = 1, - LOCAL = 2, - UNIT = 3, - GET = 4, - EXTEND = 5, - THIS = 6, - VAR = 7, - OUTPUT = 8, - INPUT = 9, - IF = 10, - ELSE = 11, - ELIF = 12, - FOR = 13, - IN = 14, - TO = 15, - BY = 16, - INT = 17, - STRING = 18, - FLOAT = 19, - BOOL = 20, - INT_LIT = 21, - FLOAT_LIT = 22, - STRING_LIT = 23, - BOOL_LIT = 24, - ID = 25, - ASSIGN = 26, - PLUS = 27, - MINUS = 28, - MUL = 29, - DIV = 30, - MOD = 31, - COLON = 32, - GT = 33, - LT = 34, - GTE = 35, - LTE = 36, - EQ = 37, - NEQ = 38, - DOT = 39, - COMMA = 40, - LPAREN = 41, - RPAREN = 42, - LBRACE = 43, - RBRACE = 44, - LBRACKET = 45, - RBRACKET = 46, - LINE_COMMENT = 47, - BLOCK_COMMENT = 48, - WS = 49, - PLUS_ASSIGN = 50, - MINUS_ASSIGN = 51, - MUL_ASSIGN = 52, - DIV_ASSIGN = 53, - TILDE_BAR = 54, - TILDE_ARROW = 55, - BUILTIN = 56, - ALL = 57, - ANY = 58, - BANG = 59, - INVALID = -2; - - private static final Map NAMES = new HashMap(); - - static { - NAMES.put(SHARE, _share); - NAMES.put(LOCAL, _local); - NAMES.put(UNIT, _unit); - NAMES.put(GET, _get); - NAMES.put(EXTEND, _extend); - NAMES.put(THIS, _this); - NAMES.put(VAR, _var); - NAMES.put(OUTPUT, _output); - NAMES.put(INPUT, _input); - NAMES.put(IF, _if); - NAMES.put(ELSE, _else); - NAMES.put(ELIF, _elif); - NAMES.put(FOR, _for); - NAMES.put(IN, _in); - NAMES.put(TO, _to); - NAMES.put(BY, _by); - NAMES.put(INT, _int); - NAMES.put(STRING, _string); - NAMES.put(FLOAT, _float); - NAMES.put(BOOL, _bool); - NAMES.put(BUILTIN, _builtin); - NAMES.put(ALL, _all); - NAMES.put(ANY, _any); - - NAMES.put(INT_LIT, _int_lit); - NAMES.put(FLOAT_LIT, _float_lit); - NAMES.put(STRING_LIT, _string_lit); - NAMES.put(BOOL_LIT, _bool_lit); - NAMES.put(ID, _id); - - NAMES.put(ASSIGN, _assign); - NAMES.put(PLUS, _plus); - NAMES.put(MINUS, _minus); - NAMES.put(MUL, _mul); - NAMES.put(DIV, _div); - NAMES.put(MOD, _mod); - NAMES.put(COLON, _colon); - NAMES.put(GT, _gt); - NAMES.put(LT, _lt); - NAMES.put(GTE, _gte); - NAMES.put(LTE, _lte); - NAMES.put(EQ, _eq); - NAMES.put(NEQ, _neq); - NAMES.put(DOT, _dot); - NAMES.put(COMMA, _comma); - NAMES.put(LPAREN, _lparen); - NAMES.put(RPAREN, _rparen); - NAMES.put(LBRACE, _lbrace); - NAMES.put(RBRACE, _rbrace); - NAMES.put(LBRACKET, _lbracket); - NAMES.put(RBRACKET, _rbracket); - NAMES.put(PLUS_ASSIGN, _plus_assign); - NAMES.put(MINUS_ASSIGN, _minus_assign); - NAMES.put(MUL_ASSIGN, _mul_assign); - NAMES.put(DIV_ASSIGN, _div_assign); - NAMES.put(BANG, _bang); - NAMES.put(TILDE_BAR, _tilde_bar); - NAMES.put(TILDE_ARROW, _tilde_arrow); - - NAMES.put(Token.EOF, _eof); - NAMES.put(INVALID, _invalid); - NAMES.put(LINE_COMMENT, _line_comment); - NAMES.put(BLOCK_COMMENT, _block_comment); - NAMES.put(WS, _ws); - } - - public static String getName(int type) { - String name = NAMES.get(type); - return name != null ? name : "UNKNOWN(" + type + ")"; - } - } - - private static final Map KEYWORDS = new HashMap(); - - static { - KEYWORDS.put(share, TokenType.SHARE); - KEYWORDS.put(local, TokenType.LOCAL); - KEYWORDS.put(unit, TokenType.UNIT); - KEYWORDS.put(get, TokenType.GET); - KEYWORDS.put(extend, TokenType.EXTEND); - KEYWORDS.put(this_, TokenType.THIS); - KEYWORDS.put(var, TokenType.VAR); - KEYWORDS.put(output, TokenType.OUTPUT); - KEYWORDS.put(input_, TokenType.INPUT); - KEYWORDS.put(if_, TokenType.IF); - KEYWORDS.put(else_, TokenType.ELSE); - KEYWORDS.put(elif_, TokenType.ELIF); - KEYWORDS.put(for_, TokenType.FOR); - KEYWORDS.put(in_, TokenType.IN); - KEYWORDS.put(to_, TokenType.TO); - KEYWORDS.put(by_, TokenType.BY); - KEYWORDS.put(int_, TokenType.INT); - KEYWORDS.put(string, TokenType.STRING); - KEYWORDS.put(float_, TokenType.FLOAT); - KEYWORDS.put(builtin, TokenType.BUILTIN); - KEYWORDS.put(bool, TokenType.BOOL); - KEYWORDS.put(true_, TokenType.BOOL_LIT); - KEYWORDS.put(false_, TokenType.BOOL_LIT); - KEYWORDS.put(all, TokenType.ALL); - KEYWORDS.put(any, TokenType.ANY); - } - - private final String input; - private int position = 0; - private int line = 1; - private int column = 1; - - public ManualCoderiveLexer(String input) { - this.input = input; - } - - public List tokenize() { - List tokens = new ArrayList(); - while (position < input.length()) { - skipWhitespaceAndComments(); - if (position < input.length()) { - tokens.add(scanNextToken()); - } - } - tokens.add(new Token(Token.EOF, "", line, column)); - return tokens; - } - - private void skipWhitespaceAndComments() { - while (position < input.length()) { - char c = peek(); - if (Character.isWhitespace(c)) { - consume(); - } else if (c == '/' && peek(1) == '/') { - scanLineComment(); - } else if (c == '/' && peek(1) == '*') { - scanBlockComment(); - } else { - break; - } - } - } - - private Token scanNextToken() { - int startLine = line; - int startColumn = column; - char c = peek(); - - if (Character.isLetter(c) || c == '_') - return readIdentifierOrKeyword(startLine, startColumn); - if (Character.isDigit(c)) return readNumber(startLine, startColumn); - if (c == '"') return readString(startLine, startColumn); - return readSymbol(startLine, startColumn); - } - - private Token readIdentifierOrKeyword(int startLine, int startColumn) { - StringBuilder sb = new StringBuilder(); - while (position < input.length() && (Character.isLetterOrDigit(peek()) || peek() == '_')) { - sb.append(consume()); - } - String text = sb.toString(); - Integer type = KEYWORDS.get(text); - return new Token(type != null ? type : TokenType.ID, text, startLine, startColumn); - } - - private Token readNumber(int startLine, int startColumn) { - StringBuilder sb = new StringBuilder(); - boolean isFloat = false; - while (position < input.length() && Character.isDigit(peek())) { - sb.append(consume()); - } - if (peek() == '.') { - isFloat = true; - sb.append(consume()); - while (position < input.length() && Character.isDigit(peek())) { - sb.append(consume()); - } - } - return new Token(isFloat ? TokenType.FLOAT_LIT : TokenType.INT_LIT, sb.toString(), startLine, startColumn); - } - - private Token readString(int startLine, int startColumn) { - StringBuilder sb = new StringBuilder(); - consume(); // Consume opening quote - while (position < input.length() && peek() != '"') { - if (peek() == '\\') { - consume(); // consume the backslash - char escaped = consume(); - switch (escaped) { - case 'n': sb.append('\n'); break; - case 't': sb.append('\t'); break; - case 'r': sb.append('\r'); break; - case '\\': sb.append('\\'); break; - case '"': sb.append('"'); break; - default: sb.append('\\').append(escaped); break; - } - } else { - sb.append(consume()); - } - } - if (position < input.length()) consume(); // Consume closing quote - return new Token(TokenType.STRING_LIT, sb.toString(), startLine, startColumn); - } - - private Token readSymbol(int startLine, int startColumn) { - char c1 = consume(); - switch (c1) { - case '=': - if (peek() == '=') { - consume(); - return new Token(TokenType.EQ, "==", startLine, startColumn); - } else { - return new Token(TokenType.ASSIGN, "=", startLine, startColumn); - } - case '>': - if (peek() == '=') { - consume(); - return new Token(TokenType.GTE, ">=", startLine, startColumn); - } else { - return new Token(TokenType.GT, ">", startLine, startColumn); - } - case '<': - if (peek() == '=') { - consume(); - return new Token(TokenType.LTE, "<=", startLine, startColumn); - } else { - return new Token(TokenType.LT, "<", startLine, startColumn); - } - case '!': - if (peek() == '=') { - consume(); - return new Token(TokenType.NEQ, "!=", startLine, startColumn); - } else { - return new Token(TokenType.BANG, "!", startLine, startColumn); - } - case '+': - if (peek() == '=') { - consume(); - return new Token(TokenType.PLUS_ASSIGN, "+=", startLine, startColumn); - } else { - return new Token(TokenType.PLUS, "+", startLine, startColumn); - } - case '-': - if (peek() == '=') { - consume(); - return new Token(TokenType.MINUS_ASSIGN, "-=", startLine, startColumn); - } else { - return new Token(TokenType.MINUS, "-", startLine, startColumn); - } - case '*': - if (peek() == '=') { - consume(); - return new Token(TokenType.MUL_ASSIGN, "*=", startLine, startColumn); - } else { - return new Token(TokenType.MUL, "*", startLine, startColumn); - } - case '/': - if (peek() == '=') { - consume(); - return new Token(TokenType.DIV_ASSIGN, "/=", startLine, startColumn); - } else { - return new Token(TokenType.DIV, "/", startLine, startColumn); - } - case '~': - if (peek() == '|') { - consume(); - return new Token(TokenType.TILDE_BAR, "~|", startLine, startColumn); - } else if (peek() == '>') { - consume(); - return new Token(TokenType.TILDE_ARROW, "~>", startLine, startColumn); - } else { - return new Token(TokenType.INVALID, "~", startLine, startColumn); - } - case '%': - return new Token(TokenType.MOD, "%", startLine, startColumn); - case ':': - return new Token(TokenType.COLON, ":", startLine, startColumn); - case '.': - return new Token(TokenType.DOT, ".", startLine, startColumn); - case ',': - return new Token(TokenType.COMMA, ",", startLine, startColumn); - case '(': - return new Token(TokenType.LPAREN, "(", startLine, startColumn); - case ')': - return new Token(TokenType.RPAREN, ")", startLine, startColumn); - case '{': - return new Token(TokenType.LBRACE, "{", startLine, startColumn); - case '}': - return new Token(TokenType.RBRACE, "}", startLine, startColumn); - case '[': - return new Token(TokenType.LBRACKET, "[", startLine, startColumn); - case ']': - return new Token(TokenType.RBRACKET, "]", startLine, startColumn); - default: - return new Token(TokenType.INVALID, String.valueOf(c1), startLine, startColumn); - } - } - - private void scanLineComment() { - while (position < input.length() && peek() != '\n') consume(); - } - - private void scanBlockComment() { - consume(); - consume(); // consume '/*' - while (position < input.length() - 1) { - if (peek() == '*' && peek(1) == '/') { - consume(); - consume(); - return; - } - consume(); - } - } - - private char peek() { - return peek(0); - } - - private char peek(int offset) { - return (position + offset >= input.length()) ? '\0' : input.charAt(position + offset); - } - - private char consume() { - char c = input.charAt(position++); - if (c == '\n') { - line++; - column = 1; - } else { - column++; - } - return c; - } -} \ No newline at end of file From bc5686e7b854b0d44c00b8f1235e70733f580a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:58:29 +0800 Subject: [PATCH 16/54] Delete src/main/java/cod/ast/ImportResolver.java --- src/main/java/cod/ast/ImportResolver.java | 329 ---------------------- 1 file changed, 329 deletions(-) delete mode 100644 src/main/java/cod/ast/ImportResolver.java diff --git a/src/main/java/cod/ast/ImportResolver.java b/src/main/java/cod/ast/ImportResolver.java deleted file mode 100644 index 58982329..00000000 --- a/src/main/java/cod/ast/ImportResolver.java +++ /dev/null @@ -1,329 +0,0 @@ -package cod.ast; - -import cod.ast.nodes.*; -import cod.debug.DebugSystem; -import java.util.*; -import java.io.*; - -public class ImportResolver { - private Map importedUnits = new HashMap<>(); - private Map loadedPrograms = new HashMap<>(); - private Map preloadedImports = new HashMap<>(); - private Set registeredImports = new HashSet<>(); - private List importPaths = new ArrayList<>(); - - public ImportResolver() { - // Initialize with default import paths - importPaths.add("."); - importPaths.add("./lib"); - importPaths.add("./imports"); - } - - public void addImportPath(String path) { - importPaths.add(path); - DebugSystem.debug("IMPORTS", "Added import path: " + path); - } - - public void registerImport(String importName) { - // Just store the import name for later resolution - if (!registeredImports.contains(importName)) { - registeredImports.add(importName); - DebugSystem.debug("IMPORTS", "Registered import (lazy): " + importName); - } - } - - private String extractImportName(String qualifiedMethodName) { - int lastDot = qualifiedMethodName.lastIndexOf('.'); - if (lastDot > 0) { - return qualifiedMethodName.substring(0, lastDot); - } - return qualifiedMethodName; - } - - private String extractMethodName(String qualifiedMethodName) { - int lastDot = qualifiedMethodName.lastIndexOf('.'); - if (lastDot > 0) { - return qualifiedMethodName.substring(lastDot + 1); - } - return qualifiedMethodName; // No dot, so it's just the method name - } - - public ProgramNode resolveImport(String importName) throws Exception { - DebugSystem.debug("IMPORTS", "resolveImport called for: " + importName); - - // Debug file system first - debugFileSystem(importName); - - // Check if already loaded - if (loadedPrograms.containsKey(importName)) { - DebugSystem.debug("IMPORTS", "Import already loaded: " + importName); - return loadedPrograms.get(importName); - } - - // Check if preloaded during AST building - if (preloadedImports.containsKey(importName)) { - DebugSystem.debug("IMPORTS", "Using preloaded import: " + importName); - ProgramNode program = preloadedImports.get(importName); - loadedPrograms.put(importName, program); - importedUnits.put(importName, program); // Also add to importedUnits for compatibility - return program; - } - - List attemptedPaths = new ArrayList<>(); - ProgramNode program = null; - - // Try different file paths and extensions - String[] basePaths = { - "", // current directory - "cod/", - "src/cod/", - "../cod/", - "/storage/emulated/0/JavaNIDE/Programming-Language/Coderive/executables/" - }; - - String[] extensions = { - ".cod", - ".txt", - "" - }; - - // Convert import name to file path (e.g., "cod.Sys" -> "cod/Sys") - String filePath = importName.replace('.', '/'); - - for (String basePath : basePaths) { - for (String extension : extensions) { - String fullPath = basePath + filePath + extension; - attemptedPaths.add(fullPath); - - try { - DebugSystem.debug("IMPORTS", "Trying path: " + fullPath); - program = loadImportFromFile(fullPath); - if (program != null) { - DebugSystem.debug("IMPORTS", "Successfully loaded import from: " + fullPath); - loadedPrograms.put(importName, program); - importedUnits.put(importName, program); // Also add to importedUnits for compatibility - return program; - } - } catch (Exception e) { - DebugSystem.debug("IMPORTS", "Failed to load from " + fullPath + ": " + e.getMessage()); - // Continue to next path - } - } - } - - // UPDATED: Better error message but still throw - if (program == null) { - String error = "Import not found: " + importName + - " (searched: " + attemptedPaths + ")"; - DebugSystem.error("IMPORTS", error); - throw new RuntimeException(error); - } - - return program; - } - - private ProgramNode loadImportFromFile(String filePath) throws Exception { - File file = new File(filePath); - if (!file.exists() || !file.isFile()) { - return null; - } - - DebugSystem.debug("IMPORTS", "Loading import from file: " + filePath); - - try { - // Read the file content - StringBuilder content = new StringBuilder(); - BufferedReader reader = new BufferedReader(new FileReader(file)); - String line; - while ((line = reader.readLine()) != null) { - content.append(line).append("\n"); - } - reader.close(); - - DebugSystem.debug("IMPORTS", "File content length: " + content.length() + " characters"); - - // Use the SAME MANUAL parser that we use for the main file - ManualCoderiveLexer lexer = new ManualCoderiveLexer(content.toString()); - List tokens = lexer.tokenize(); - - DebugSystem.debug("IMPORTS", "Generated " + tokens.size() + " tokens"); - - ManualCoderiveParser parser = new ManualCoderiveParser(tokens); - ProgramNode program = parser.parseProgram(); - - DebugSystem.debug("IMPORTS", "Successfully parsed import file using manual parser: " + filePath); - return program; - - } catch (Exception e) { - DebugSystem.error("IMPORTS", "Failed to parse import file: " + filePath + " - " + e.getMessage()); - e.printStackTrace(); - throw new RuntimeException("Failed to parse import file: " + filePath + " - " + e.getMessage(), e); - } - } - - public MethodNode findMethod(String qualifiedMethodName) { - DebugSystem.debug("IMPORTS", "findMethod called for: " + qualifiedMethodName); - - // Extract method name and potential import name - int lastDot = qualifiedMethodName.lastIndexOf('.'); - if (lastDot == -1) { - DebugSystem.debug("IMPORTS", "No dots in method name, not an imported method"); - return null; // Not an imported method - } - - String methodName = qualifiedMethodName.substring(lastDot + 1); - String calledImport = qualifiedMethodName.substring(0, lastDot); // This is "Sys" from "Sys.outln" - - DebugSystem.debug("IMPORTS", "Called import part: '" + calledImport + "', method: '" + methodName + "'"); - - // FIX: First check if we already have a loaded import that matches - String actualImportName = null; - - // Check loaded imports first - for (String loadedImport : loadedPrograms.keySet()) { - DebugSystem.debug("IMPORTS", "Checking loaded import: " + loadedImport); - - // Check if loaded import ends with the called import - // e.g., "cod.Sys" ends with ".Sys" and calledImport is "Sys" - if (loadedImport.endsWith("." + calledImport) || loadedImport.equals(calledImport)) { - actualImportName = loadedImport; - DebugSystem.debug("IMPORTS", "Found matching loaded import: " + actualImportName); - break; - } - } - - // If not found in loaded imports, check registered imports - if (actualImportName == null) { - for (String registeredImport : registeredImports) { - DebugSystem.debug("IMPORTS", "Checking registered import: " + registeredImport); - - // Check if registered import ends with the called import - if (registeredImport.endsWith("." + calledImport) || registeredImport.equals(calledImport)) { - actualImportName = registeredImport; - DebugSystem.debug("IMPORTS", "Found matching registered import: " + actualImportName); - break; - } - } - } - - // If still not found, use the called import as-is - if (actualImportName == null) { - actualImportName = calledImport; - DebugSystem.debug("IMPORTS", "No import matched, using: " + actualImportName); - } - - DebugSystem.debug("IMPORTS", "Final import to resolve: '" + actualImportName + "', method: '" + methodName + "'"); - - // Try to resolve the import if not already loaded - if (!loadedPrograms.containsKey(actualImportName)) { - DebugSystem.debug("IMPORTS", "Import not loaded, trying to resolve: " + actualImportName); - try { - ProgramNode program = resolveImport(actualImportName); - if (program != null) { - loadedPrograms.put(actualImportName, program); - importedUnits.put(actualImportName, program); - registeredImports.remove(actualImportName); - DebugSystem.debug("IMPORTS", "Successfully loaded import: " + actualImportName); - } - } catch (Exception e) { - DebugSystem.error("IMPORTS", "Failed to load import " + actualImportName + ": " + e.getMessage()); - return null; - } - } - - // Search through loaded programs for the method - DebugSystem.debug("IMPORTS", "Searching for method '" + methodName + "' in loaded program: " + actualImportName); - - ProgramNode program = loadedPrograms.get(actualImportName); - if (program != null && program.unit != null && program.unit.types != null) { - for (TypeNode type : program.unit.types) { - DebugSystem.debug("IMPORTS", " Searching in type: " + type.name); - - for (MethodNode method : type.methods) { - DebugSystem.debug("IMPORTS", " Checking method: " + method.name); - if (method.name.equals(methodName)) { - DebugSystem.debug("IMPORTS", " *** FOUND METHOD: " + method.name + " ***"); - return method; - } - } - } - } - - // Method not found - DebugSystem.error("IMPORTS", "*** METHOD NOT FOUND: " + qualifiedMethodName + " ***"); - DebugSystem.debug("IMPORTS", "Loaded imports: " + loadedPrograms.keySet()); - DebugSystem.debug("IMPORTS", "Registered imports: " + registeredImports); - - return null; - } - - public void debugFileSystem(String importName) { - DebugSystem.debug("FILE_SYSTEM", "=== FILE SYSTEM DEBUG for: " + importName + " ==="); - - String filePath = importName.replace('.', '/') + ".cod"; - DebugSystem.debug("FILE_SYSTEM", "Looking for: " + filePath); - DebugSystem.debug("FILE_SYSTEM", "Import paths: " + importPaths); - - for (String basePath : importPaths) { - File file = new File(basePath, filePath); - DebugSystem.debug("FILE_SYSTEM", "Path: " + file.getAbsolutePath() + - " [exists: " + file.exists() + ", isFile: " + file.isFile() + "]"); - - // Also check the directory - File dir = file.getParentFile(); - if (dir != null && dir.exists()) { - DebugSystem.debug("FILE_SYSTEM", "Directory contents of " + dir.getAbsolutePath() + ":"); - String[] files = dir.list(); - if (files != null) { - for (String f : files) { - DebugSystem.debug("FILE_SYSTEM", " - " + f); - } - } - } - } - DebugSystem.debug("FILE_SYSTEM", "=== END FILE SYSTEM DEBUG ==="); - } - - public void debugImportStatus() { - DebugSystem.debug("IMPORTS", "=== IMPORT RESOLVER STATUS ==="); - DebugSystem.debug("IMPORTS", "Import paths: " + importPaths); - DebugSystem.debug("IMPORTS", "Loaded imports: " + importedUnits.keySet()); - DebugSystem.debug("IMPORTS", "Registered imports (lazy): " + registeredImports); - - for (Map.Entry entry : importedUnits.entrySet()) { - String unitName = entry.getKey(); - ProgramNode program = entry.getValue(); - DebugSystem.debug("IMPORTS", "Unit: " + unitName); - if (program != null && program.unit != null && program.unit.types != null) { - for (TypeNode type : program.unit.types) { - DebugSystem.debug("IMPORTS", " Type: " + type.name); - for (MethodNode method : type.methods) { - DebugSystem.debug( - "IMPORTS", - " Method: " - + method.name - + " (params: " - + method.parameters.size() - + ")"); - } - } - } - } - DebugSystem.debug("IMPORTS", "=== END IMPORT STATUS ==="); - } - - public void preloadImport(String qualifiedName, ProgramNode program) { - importedUnits.put(qualifiedName, program); - loadedPrograms.put(qualifiedName, program); - preloadedImports.put(qualifiedName, program); - DebugSystem.debug("IMPORTS", "Pre-loaded import into resolver: " + qualifiedName); - } - - public Set getLoadedImports() { - return importedUnits.keySet(); - } - - public Set getRegisteredImports() { - return new HashSet<>(registeredImports); - } -} \ No newline at end of file From e92388775ed372e1e2ced2346864b23f11049450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:58:40 +0800 Subject: [PATCH 17/54] Delete src/main/java/cod/ast/CoderiveParserVisitor.java --- .../java/cod/ast/CoderiveParserVisitor.java | 401 ------------------ 1 file changed, 401 deletions(-) delete mode 100644 src/main/java/cod/ast/CoderiveParserVisitor.java diff --git a/src/main/java/cod/ast/CoderiveParserVisitor.java b/src/main/java/cod/ast/CoderiveParserVisitor.java deleted file mode 100644 index 7cdd572d..00000000 --- a/src/main/java/cod/ast/CoderiveParserVisitor.java +++ /dev/null @@ -1,401 +0,0 @@ -// Generated from CoderiveParser.g4 by ANTLR 4.13.2 - -package cod.ast; - -import org.antlr.v4.runtime.tree.ParseTreeVisitor; - -/** - * This interface defines a complete generic visitor for a parse tree produced - * by {@link CoderiveParser}. - * - * @param The return type of the visit operation. Use {@link Void} for - * operations with no return type. - */ -public interface CoderiveParserVisitor extends ParseTreeVisitor { - /** - * Visit a parse tree produced by {@link CoderiveParser#program}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitProgram(CoderiveParser.ProgramContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#unitDeclaration}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitUnitDeclaration(CoderiveParser.UnitDeclarationContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#qualifiedNameList}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitQualifiedNameList(CoderiveParser.QualifiedNameListContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#qualifiedName}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitQualifiedName(CoderiveParser.QualifiedNameContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#typeDeclaration}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitTypeDeclaration(CoderiveParser.TypeDeclarationContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#modifiers}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitModifiers(CoderiveParser.ModifiersContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#typeBody}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitTypeBody(CoderiveParser.TypeBodyContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#fieldDeclaration}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitFieldDeclaration(CoderiveParser.FieldDeclarationContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#constructor}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitConstructor(CoderiveParser.ConstructorContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#methodDeclaration}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitMethodDeclaration(CoderiveParser.MethodDeclarationContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#idList}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitIdList(CoderiveParser.IdListContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#slotList}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitSlotList(CoderiveParser.SlotListContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#parameterList}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitParameterList(CoderiveParser.ParameterListContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#parameter}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitParameter(CoderiveParser.ParameterContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#type}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitType(CoderiveParser.TypeContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#simpleType}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitSimpleType(CoderiveParser.SimpleTypeContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#statement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitStatement(CoderiveParser.StatementContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#variableDeclaration}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitVariableDeclaration(CoderiveParser.VariableDeclarationContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#assignment}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitAssignment(CoderiveParser.AssignmentContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#expressionStatement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitExpressionStatement(CoderiveParser.ExpressionStatementContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#assignable}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitAssignable(CoderiveParser.AssignableContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#returnSlotAssignment}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitReturnSlotAssignment(CoderiveParser.ReturnSlotAssignmentContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#assignableList}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitAssignableList(CoderiveParser.AssignableListContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#slotMethodCallStatement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitSlotMethodCallStatement(CoderiveParser.SlotMethodCallStatementContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#slotMethodCall}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitSlotMethodCall(CoderiveParser.SlotMethodCallContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#slotCast}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitSlotCast(CoderiveParser.SlotCastContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#inputAssignment}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitInputAssignment(CoderiveParser.InputAssignmentContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#inputStatement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitInputStatement(CoderiveParser.InputStatementContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#typeInput}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitTypeInput(CoderiveParser.TypeInputContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#outputStatement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitOutputStatement(CoderiveParser.OutputStatementContext ctx); - /** - * Visit a parse tree produced by the {@code outputSlotCall} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitOutputSlotCall(CoderiveParser.OutputSlotCallContext ctx); - /** - * Visit a parse tree produced by the {@code outputNamedAssignment} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitOutputNamedAssignment(CoderiveParser.OutputNamedAssignmentContext ctx); - /** - * Visit a parse tree produced by the {@code outputExpression} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitOutputExpression(CoderiveParser.OutputExpressionContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#methodCallStatement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitMethodCallStatement(CoderiveParser.MethodCallStatementContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#methodCall}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitMethodCall(CoderiveParser.MethodCallContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#argumentList}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitArgumentList(CoderiveParser.ArgumentListContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#ifStatement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitIfStatement(CoderiveParser.IfStatementContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#thenBlock}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitThenBlock(CoderiveParser.ThenBlockContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#elseBlock}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitElseBlock(CoderiveParser.ElseBlockContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#forStatement}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitForStatement(CoderiveParser.ForStatementContext ctx); - /** - * Visit a parse tree produced by the {@code operatorStep} - * labeled alternative in {@link CoderiveParser#forStepExpr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitOperatorStep(CoderiveParser.OperatorStepContext ctx); - /** - * Visit a parse tree produced by the {@code regularStep} - * labeled alternative in {@link CoderiveParser#forStepExpr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitRegularStep(CoderiveParser.RegularStepContext ctx); - /** - * Visit a parse tree produced by the {@code methodCallExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitMethodCallExpr(CoderiveParser.MethodCallExprContext ctx); - /** - * Visit a parse tree produced by the {@code unaryExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitUnaryExpr(CoderiveParser.UnaryExprContext ctx); - /** - * Visit a parse tree produced by the {@code primaryExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitPrimaryExpr(CoderiveParser.PrimaryExprContext ctx); - /** - * Visit a parse tree produced by the {@code comparisonExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitComparisonExpr(CoderiveParser.ComparisonExprContext ctx); - /** - * Visit a parse tree produced by the {@code typeCastExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitTypeCastExpr(CoderiveParser.TypeCastExprContext ctx); - /** - * Visit a parse tree produced by the {@code additiveExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitAdditiveExpr(CoderiveParser.AdditiveExprContext ctx); - /** - * Visit a parse tree produced by the {@code multiplicativeExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitMultiplicativeExpr(CoderiveParser.MultiplicativeExprContext ctx); - /** - * Visit a parse tree produced by the {@code indexAccessExpr} - * labeled alternative in {@link CoderiveParser#primary}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitIndexAccessExpr(CoderiveParser.IndexAccessExprContext ctx); - /** - * Visit a parse tree produced by the {@code identifierExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitIdentifierExpr(CoderiveParser.IdentifierExprContext ctx); - /** - * Visit a parse tree produced by the {@code intLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitIntLiteralExpr(CoderiveParser.IntLiteralExprContext ctx); - /** - * Visit a parse tree produced by the {@code floatLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitFloatLiteralExpr(CoderiveParser.FloatLiteralExprContext ctx); - /** - * Visit a parse tree produced by the {@code stringLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitStringLiteralExpr(CoderiveParser.StringLiteralExprContext ctx); - /** - * Visit a parse tree produced by the {@code boolLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitBoolLiteralExpr(CoderiveParser.BoolLiteralExprContext ctx); - /** - * Visit a parse tree produced by the {@code parenthesizedExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitParenthesizedExpr(CoderiveParser.ParenthesizedExprContext ctx); - /** - * Visit a parse tree produced by the {@code arrayLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitArrayLiteralExpr(CoderiveParser.ArrayLiteralExprContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#arrayLiteral}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitArrayLiteral(CoderiveParser.ArrayLiteralContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#exprList}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitExprList(CoderiveParser.ExprListContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#indexAccess}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitIndexAccess(CoderiveParser.IndexAccessContext ctx); - /** - * Visit a parse tree produced by {@link CoderiveParser#typeCast}. - * @param ctx the parse tree - * @return the visitor result - */ - T visitTypeCast(CoderiveParser.TypeCastContext ctx); -} \ No newline at end of file From 82ee37afb8120e7af6f1234835b2adb0981e8ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:58:50 +0800 Subject: [PATCH 18/54] Delete src/main/java/cod/ast/CoderiveParserListener.java --- .../java/cod/ast/CoderiveParserListener.java | 662 ------------------ 1 file changed, 662 deletions(-) delete mode 100644 src/main/java/cod/ast/CoderiveParserListener.java diff --git a/src/main/java/cod/ast/CoderiveParserListener.java b/src/main/java/cod/ast/CoderiveParserListener.java deleted file mode 100644 index 8f1eb925..00000000 --- a/src/main/java/cod/ast/CoderiveParserListener.java +++ /dev/null @@ -1,662 +0,0 @@ -// Generated from CoderiveParser.g4 by ANTLR 4.13.2 - -package cod.ast; - -import org.antlr.v4.runtime.tree.ParseTreeListener; - -/** - * This interface defines a complete listener for a parse tree produced by - * {@link CoderiveParser}. - */ -public interface CoderiveParserListener extends ParseTreeListener { - /** - * Enter a parse tree produced by {@link CoderiveParser#program}. - * @param ctx the parse tree - */ - void enterProgram(CoderiveParser.ProgramContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#program}. - * @param ctx the parse tree - */ - void exitProgram(CoderiveParser.ProgramContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#unitDeclaration}. - * @param ctx the parse tree - */ - void enterUnitDeclaration(CoderiveParser.UnitDeclarationContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#unitDeclaration}. - * @param ctx the parse tree - */ - void exitUnitDeclaration(CoderiveParser.UnitDeclarationContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#qualifiedNameList}. - * @param ctx the parse tree - */ - void enterQualifiedNameList(CoderiveParser.QualifiedNameListContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#qualifiedNameList}. - * @param ctx the parse tree - */ - void exitQualifiedNameList(CoderiveParser.QualifiedNameListContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#qualifiedName}. - * @param ctx the parse tree - */ - void enterQualifiedName(CoderiveParser.QualifiedNameContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#qualifiedName}. - * @param ctx the parse tree - */ - void exitQualifiedName(CoderiveParser.QualifiedNameContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#typeDeclaration}. - * @param ctx the parse tree - */ - void enterTypeDeclaration(CoderiveParser.TypeDeclarationContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#typeDeclaration}. - * @param ctx the parse tree - */ - void exitTypeDeclaration(CoderiveParser.TypeDeclarationContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#modifiers}. - * @param ctx the parse tree - */ - void enterModifiers(CoderiveParser.ModifiersContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#modifiers}. - * @param ctx the parse tree - */ - void exitModifiers(CoderiveParser.ModifiersContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#typeBody}. - * @param ctx the parse tree - */ - void enterTypeBody(CoderiveParser.TypeBodyContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#typeBody}. - * @param ctx the parse tree - */ - void exitTypeBody(CoderiveParser.TypeBodyContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#fieldDeclaration}. - * @param ctx the parse tree - */ - void enterFieldDeclaration(CoderiveParser.FieldDeclarationContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#fieldDeclaration}. - * @param ctx the parse tree - */ - void exitFieldDeclaration(CoderiveParser.FieldDeclarationContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#constructor}. - * @param ctx the parse tree - */ - void enterConstructor(CoderiveParser.ConstructorContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#constructor}. - * @param ctx the parse tree - */ - void exitConstructor(CoderiveParser.ConstructorContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#methodDeclaration}. - * @param ctx the parse tree - */ - void enterMethodDeclaration(CoderiveParser.MethodDeclarationContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#methodDeclaration}. - * @param ctx the parse tree - */ - void exitMethodDeclaration(CoderiveParser.MethodDeclarationContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#idList}. - * @param ctx the parse tree - */ - void enterIdList(CoderiveParser.IdListContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#idList}. - * @param ctx the parse tree - */ - void exitIdList(CoderiveParser.IdListContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#slotList}. - * @param ctx the parse tree - */ - void enterSlotList(CoderiveParser.SlotListContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#slotList}. - * @param ctx the parse tree - */ - void exitSlotList(CoderiveParser.SlotListContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#parameterList}. - * @param ctx the parse tree - */ - void enterParameterList(CoderiveParser.ParameterListContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#parameterList}. - * @param ctx the parse tree - */ - void exitParameterList(CoderiveParser.ParameterListContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#parameter}. - * @param ctx the parse tree - */ - void enterParameter(CoderiveParser.ParameterContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#parameter}. - * @param ctx the parse tree - */ - void exitParameter(CoderiveParser.ParameterContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#type}. - * @param ctx the parse tree - */ - void enterType(CoderiveParser.TypeContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#type}. - * @param ctx the parse tree - */ - void exitType(CoderiveParser.TypeContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#simpleType}. - * @param ctx the parse tree - */ - void enterSimpleType(CoderiveParser.SimpleTypeContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#simpleType}. - * @param ctx the parse tree - */ - void exitSimpleType(CoderiveParser.SimpleTypeContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#statement}. - * @param ctx the parse tree - */ - void enterStatement(CoderiveParser.StatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#statement}. - * @param ctx the parse tree - */ - void exitStatement(CoderiveParser.StatementContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#variableDeclaration}. - * @param ctx the parse tree - */ - void enterVariableDeclaration(CoderiveParser.VariableDeclarationContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#variableDeclaration}. - * @param ctx the parse tree - */ - void exitVariableDeclaration(CoderiveParser.VariableDeclarationContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#assignment}. - * @param ctx the parse tree - */ - void enterAssignment(CoderiveParser.AssignmentContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#assignment}. - * @param ctx the parse tree - */ - void exitAssignment(CoderiveParser.AssignmentContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#expressionStatement}. - * @param ctx the parse tree - */ - void enterExpressionStatement(CoderiveParser.ExpressionStatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#expressionStatement}. - * @param ctx the parse tree - */ - void exitExpressionStatement(CoderiveParser.ExpressionStatementContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#assignable}. - * @param ctx the parse tree - */ - void enterAssignable(CoderiveParser.AssignableContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#assignable}. - * @param ctx the parse tree - */ - void exitAssignable(CoderiveParser.AssignableContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#returnSlotAssignment}. - * @param ctx the parse tree - */ - void enterReturnSlotAssignment(CoderiveParser.ReturnSlotAssignmentContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#returnSlotAssignment}. - * @param ctx the parse tree - */ - void exitReturnSlotAssignment(CoderiveParser.ReturnSlotAssignmentContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#assignableList}. - * @param ctx the parse tree - */ - void enterAssignableList(CoderiveParser.AssignableListContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#assignableList}. - * @param ctx the parse tree - */ - void exitAssignableList(CoderiveParser.AssignableListContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#slotMethodCallStatement}. - * @param ctx the parse tree - */ - void enterSlotMethodCallStatement(CoderiveParser.SlotMethodCallStatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#slotMethodCallStatement}. - * @param ctx the parse tree - */ - void exitSlotMethodCallStatement(CoderiveParser.SlotMethodCallStatementContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#slotMethodCall}. - * @param ctx the parse tree - */ - void enterSlotMethodCall(CoderiveParser.SlotMethodCallContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#slotMethodCall}. - * @param ctx the parse tree - */ - void exitSlotMethodCall(CoderiveParser.SlotMethodCallContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#slotCast}. - * @param ctx the parse tree - */ - void enterSlotCast(CoderiveParser.SlotCastContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#slotCast}. - * @param ctx the parse tree - */ - void exitSlotCast(CoderiveParser.SlotCastContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#inputAssignment}. - * @param ctx the parse tree - */ - void enterInputAssignment(CoderiveParser.InputAssignmentContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#inputAssignment}. - * @param ctx the parse tree - */ - void exitInputAssignment(CoderiveParser.InputAssignmentContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#inputStatement}. - * @param ctx the parse tree - */ - void enterInputStatement(CoderiveParser.InputStatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#inputStatement}. - * @param ctx the parse tree - */ - void exitInputStatement(CoderiveParser.InputStatementContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#typeInput}. - * @param ctx the parse tree - */ - void enterTypeInput(CoderiveParser.TypeInputContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#typeInput}. - * @param ctx the parse tree - */ - void exitTypeInput(CoderiveParser.TypeInputContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#outputStatement}. - * @param ctx the parse tree - */ - void enterOutputStatement(CoderiveParser.OutputStatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#outputStatement}. - * @param ctx the parse tree - */ - void exitOutputStatement(CoderiveParser.OutputStatementContext ctx); - /** - * Enter a parse tree produced by the {@code outputSlotCall} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - */ - void enterOutputSlotCall(CoderiveParser.OutputSlotCallContext ctx); - /** - * Exit a parse tree produced by the {@code outputSlotCall} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - */ - void exitOutputSlotCall(CoderiveParser.OutputSlotCallContext ctx); - /** - * Enter a parse tree produced by the {@code outputNamedAssignment} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - */ - void enterOutputNamedAssignment(CoderiveParser.OutputNamedAssignmentContext ctx); - /** - * Exit a parse tree produced by the {@code outputNamedAssignment} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - */ - void exitOutputNamedAssignment(CoderiveParser.OutputNamedAssignmentContext ctx); - /** - * Enter a parse tree produced by the {@code outputExpression} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - */ - void enterOutputExpression(CoderiveParser.OutputExpressionContext ctx); - /** - * Exit a parse tree produced by the {@code outputExpression} - * labeled alternative in {@link CoderiveParser#outputTarget}. - * @param ctx the parse tree - */ - void exitOutputExpression(CoderiveParser.OutputExpressionContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#methodCallStatement}. - * @param ctx the parse tree - */ - void enterMethodCallStatement(CoderiveParser.MethodCallStatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#methodCallStatement}. - * @param ctx the parse tree - */ - void exitMethodCallStatement(CoderiveParser.MethodCallStatementContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#methodCall}. - * @param ctx the parse tree - */ - void enterMethodCall(CoderiveParser.MethodCallContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#methodCall}. - * @param ctx the parse tree - */ - void exitMethodCall(CoderiveParser.MethodCallContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#argumentList}. - * @param ctx the parse tree - */ - void enterArgumentList(CoderiveParser.ArgumentListContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#argumentList}. - * @param ctx the parse tree - */ - void exitArgumentList(CoderiveParser.ArgumentListContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#ifStatement}. - * @param ctx the parse tree - */ - void enterIfStatement(CoderiveParser.IfStatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#ifStatement}. - * @param ctx the parse tree - */ - void exitIfStatement(CoderiveParser.IfStatementContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#thenBlock}. - * @param ctx the parse tree - */ - void enterThenBlock(CoderiveParser.ThenBlockContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#thenBlock}. - * @param ctx the parse tree - */ - void exitThenBlock(CoderiveParser.ThenBlockContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#elseBlock}. - * @param ctx the parse tree - */ - void enterElseBlock(CoderiveParser.ElseBlockContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#elseBlock}. - * @param ctx the parse tree - */ - void exitElseBlock(CoderiveParser.ElseBlockContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#forStatement}. - * @param ctx the parse tree - */ - void enterForStatement(CoderiveParser.ForStatementContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#forStatement}. - * @param ctx the parse tree - */ - void exitForStatement(CoderiveParser.ForStatementContext ctx); - /** - * Enter a parse tree produced by the {@code operatorStep} - * labeled alternative in {@link CoderiveParser#forStepExpr}. - * @param ctx the parse tree - */ - void enterOperatorStep(CoderiveParser.OperatorStepContext ctx); - /** - * Exit a parse tree produced by the {@code operatorStep} - * labeled alternative in {@link CoderiveParser#forStepExpr}. - * @param ctx the parse tree - */ - void exitOperatorStep(CoderiveParser.OperatorStepContext ctx); - /** - * Enter a parse tree produced by the {@code regularStep} - * labeled alternative in {@link CoderiveParser#forStepExpr}. - * @param ctx the parse tree - */ - void enterRegularStep(CoderiveParser.RegularStepContext ctx); - /** - * Exit a parse tree produced by the {@code regularStep} - * labeled alternative in {@link CoderiveParser#forStepExpr}. - * @param ctx the parse tree - */ - void exitRegularStep(CoderiveParser.RegularStepContext ctx); - /** - * Enter a parse tree produced by the {@code methodCallExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void enterMethodCallExpr(CoderiveParser.MethodCallExprContext ctx); - /** - * Exit a parse tree produced by the {@code methodCallExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void exitMethodCallExpr(CoderiveParser.MethodCallExprContext ctx); - /** - * Enter a parse tree produced by the {@code unaryExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void enterUnaryExpr(CoderiveParser.UnaryExprContext ctx); - /** - * Exit a parse tree produced by the {@code unaryExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void exitUnaryExpr(CoderiveParser.UnaryExprContext ctx); - /** - * Enter a parse tree produced by the {@code primaryExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void enterPrimaryExpr(CoderiveParser.PrimaryExprContext ctx); - /** - * Exit a parse tree produced by the {@code primaryExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void exitPrimaryExpr(CoderiveParser.PrimaryExprContext ctx); - /** - * Enter a parse tree produced by the {@code comparisonExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void enterComparisonExpr(CoderiveParser.ComparisonExprContext ctx); - /** - * Exit a parse tree produced by the {@code comparisonExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void exitComparisonExpr(CoderiveParser.ComparisonExprContext ctx); - /** - * Enter a parse tree produced by the {@code typeCastExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void enterTypeCastExpr(CoderiveParser.TypeCastExprContext ctx); - /** - * Exit a parse tree produced by the {@code typeCastExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void exitTypeCastExpr(CoderiveParser.TypeCastExprContext ctx); - /** - * Enter a parse tree produced by the {@code additiveExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void enterAdditiveExpr(CoderiveParser.AdditiveExprContext ctx); - /** - * Exit a parse tree produced by the {@code additiveExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void exitAdditiveExpr(CoderiveParser.AdditiveExprContext ctx); - /** - * Enter a parse tree produced by the {@code multiplicativeExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void enterMultiplicativeExpr(CoderiveParser.MultiplicativeExprContext ctx); - /** - * Exit a parse tree produced by the {@code multiplicativeExpr} - * labeled alternative in {@link CoderiveParser#expr}. - * @param ctx the parse tree - */ - void exitMultiplicativeExpr(CoderiveParser.MultiplicativeExprContext ctx); - /** - * Enter a parse tree produced by the {@code indexAccessExpr} - * labeled alternative in {@link CoderiveParser#primary}. - * @param ctx the parse tree - */ - void enterIndexAccessExpr(CoderiveParser.IndexAccessExprContext ctx); - /** - * Exit a parse tree produced by the {@code indexAccessExpr} - * labeled alternative in {@link CoderiveParser#primary}. - * @param ctx the parse tree - */ - void exitIndexAccessExpr(CoderiveParser.IndexAccessExprContext ctx); - /** - * Enter a parse tree produced by the {@code identifierExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void enterIdentifierExpr(CoderiveParser.IdentifierExprContext ctx); - /** - * Exit a parse tree produced by the {@code identifierExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void exitIdentifierExpr(CoderiveParser.IdentifierExprContext ctx); - /** - * Enter a parse tree produced by the {@code intLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void enterIntLiteralExpr(CoderiveParser.IntLiteralExprContext ctx); - /** - * Exit a parse tree produced by the {@code intLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void exitIntLiteralExpr(CoderiveParser.IntLiteralExprContext ctx); - /** - * Enter a parse tree produced by the {@code floatLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void enterFloatLiteralExpr(CoderiveParser.FloatLiteralExprContext ctx); - /** - * Exit a parse tree produced by the {@code floatLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void exitFloatLiteralExpr(CoderiveParser.FloatLiteralExprContext ctx); - /** - * Enter a parse tree produced by the {@code stringLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void enterStringLiteralExpr(CoderiveParser.StringLiteralExprContext ctx); - /** - * Exit a parse tree produced by the {@code stringLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void exitStringLiteralExpr(CoderiveParser.StringLiteralExprContext ctx); - /** - * Enter a parse tree produced by the {@code boolLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void enterBoolLiteralExpr(CoderiveParser.BoolLiteralExprContext ctx); - /** - * Exit a parse tree produced by the {@code boolLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void exitBoolLiteralExpr(CoderiveParser.BoolLiteralExprContext ctx); - /** - * Enter a parse tree produced by the {@code parenthesizedExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void enterParenthesizedExpr(CoderiveParser.ParenthesizedExprContext ctx); - /** - * Exit a parse tree produced by the {@code parenthesizedExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void exitParenthesizedExpr(CoderiveParser.ParenthesizedExprContext ctx); - /** - * Enter a parse tree produced by the {@code arrayLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void enterArrayLiteralExpr(CoderiveParser.ArrayLiteralExprContext ctx); - /** - * Exit a parse tree produced by the {@code arrayLiteralExpr} - * labeled alternative in {@link CoderiveParser#atom}. - * @param ctx the parse tree - */ - void exitArrayLiteralExpr(CoderiveParser.ArrayLiteralExprContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#arrayLiteral}. - * @param ctx the parse tree - */ - void enterArrayLiteral(CoderiveParser.ArrayLiteralContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#arrayLiteral}. - * @param ctx the parse tree - */ - void exitArrayLiteral(CoderiveParser.ArrayLiteralContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#exprList}. - * @param ctx the parse tree - */ - void enterExprList(CoderiveParser.ExprListContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#exprList}. - * @param ctx the parse tree - */ - void exitExprList(CoderiveParser.ExprListContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#indexAccess}. - * @param ctx the parse tree - */ - void enterIndexAccess(CoderiveParser.IndexAccessContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#indexAccess}. - * @param ctx the parse tree - */ - void exitIndexAccess(CoderiveParser.IndexAccessContext ctx); - /** - * Enter a parse tree produced by {@link CoderiveParser#typeCast}. - * @param ctx the parse tree - */ - void enterTypeCast(CoderiveParser.TypeCastContext ctx); - /** - * Exit a parse tree produced by {@link CoderiveParser#typeCast}. - * @param ctx the parse tree - */ - void exitTypeCast(CoderiveParser.TypeCastContext ctx); -} \ No newline at end of file From c93cc37b136265b8c4aa1b8270c743d4c91099c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:59:03 +0800 Subject: [PATCH 19/54] Delete src/main/java/cod/ast/CoderiveParserBaseVisitor.java --- .../cod/ast/CoderiveParserBaseVisitor.java | 444 ------------------ 1 file changed, 444 deletions(-) delete mode 100644 src/main/java/cod/ast/CoderiveParserBaseVisitor.java diff --git a/src/main/java/cod/ast/CoderiveParserBaseVisitor.java b/src/main/java/cod/ast/CoderiveParserBaseVisitor.java deleted file mode 100644 index 40eb6049..00000000 --- a/src/main/java/cod/ast/CoderiveParserBaseVisitor.java +++ /dev/null @@ -1,444 +0,0 @@ -// Generated from CoderiveParser.g4 by ANTLR 4.13.2 - -package cod.ast; - -import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; - -/** - * This class provides an empty implementation of {@link CoderiveParserVisitor}, - * which can be extended to create a visitor which only needs to handle a subset - * of the available methods. - * - * @param The return type of the visit operation. Use {@link Void} for - * operations with no return type. - */ -@SuppressWarnings("CheckReturnValue") -public class CoderiveParserBaseVisitor extends AbstractParseTreeVisitor implements CoderiveParserVisitor { - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitProgram(CoderiveParser.ProgramContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitUnitDeclaration(CoderiveParser.UnitDeclarationContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitQualifiedNameList(CoderiveParser.QualifiedNameListContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitQualifiedName(CoderiveParser.QualifiedNameContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitTypeDeclaration(CoderiveParser.TypeDeclarationContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitModifiers(CoderiveParser.ModifiersContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitTypeBody(CoderiveParser.TypeBodyContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitFieldDeclaration(CoderiveParser.FieldDeclarationContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitConstructor(CoderiveParser.ConstructorContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitMethodDeclaration(CoderiveParser.MethodDeclarationContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitIdList(CoderiveParser.IdListContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitSlotList(CoderiveParser.SlotListContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitParameterList(CoderiveParser.ParameterListContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitParameter(CoderiveParser.ParameterContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitType(CoderiveParser.TypeContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitSimpleType(CoderiveParser.SimpleTypeContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitStatement(CoderiveParser.StatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitVariableDeclaration(CoderiveParser.VariableDeclarationContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitAssignment(CoderiveParser.AssignmentContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitExpressionStatement(CoderiveParser.ExpressionStatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitAssignable(CoderiveParser.AssignableContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitReturnSlotAssignment(CoderiveParser.ReturnSlotAssignmentContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitAssignableList(CoderiveParser.AssignableListContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitSlotMethodCallStatement(CoderiveParser.SlotMethodCallStatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitSlotMethodCall(CoderiveParser.SlotMethodCallContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitSlotCast(CoderiveParser.SlotCastContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitInputAssignment(CoderiveParser.InputAssignmentContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitInputStatement(CoderiveParser.InputStatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitTypeInput(CoderiveParser.TypeInputContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitOutputStatement(CoderiveParser.OutputStatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitOutputSlotCall(CoderiveParser.OutputSlotCallContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitOutputNamedAssignment(CoderiveParser.OutputNamedAssignmentContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitOutputExpression(CoderiveParser.OutputExpressionContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitMethodCallStatement(CoderiveParser.MethodCallStatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitMethodCall(CoderiveParser.MethodCallContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitArgumentList(CoderiveParser.ArgumentListContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitIfStatement(CoderiveParser.IfStatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitThenBlock(CoderiveParser.ThenBlockContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitElseBlock(CoderiveParser.ElseBlockContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitForStatement(CoderiveParser.ForStatementContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitOperatorStep(CoderiveParser.OperatorStepContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitRegularStep(CoderiveParser.RegularStepContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitMethodCallExpr(CoderiveParser.MethodCallExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitUnaryExpr(CoderiveParser.UnaryExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitPrimaryExpr(CoderiveParser.PrimaryExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitComparisonExpr(CoderiveParser.ComparisonExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitTypeCastExpr(CoderiveParser.TypeCastExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitAdditiveExpr(CoderiveParser.AdditiveExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitMultiplicativeExpr(CoderiveParser.MultiplicativeExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitIndexAccessExpr(CoderiveParser.IndexAccessExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitIdentifierExpr(CoderiveParser.IdentifierExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitIntLiteralExpr(CoderiveParser.IntLiteralExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitFloatLiteralExpr(CoderiveParser.FloatLiteralExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitStringLiteralExpr(CoderiveParser.StringLiteralExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitBoolLiteralExpr(CoderiveParser.BoolLiteralExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitParenthesizedExpr(CoderiveParser.ParenthesizedExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitArrayLiteralExpr(CoderiveParser.ArrayLiteralExprContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitArrayLiteral(CoderiveParser.ArrayLiteralContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitExprList(CoderiveParser.ExprListContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitIndexAccess(CoderiveParser.IndexAccessContext ctx) { return visitChildren(ctx); } - /** - * {@inheritDoc} - * - *

The default implementation returns the result of calling - * {@link #visitChildren} on {@code ctx}.

- */ - @Override public T visitTypeCast(CoderiveParser.TypeCastContext ctx) { return visitChildren(ctx); } -} \ No newline at end of file From 2c0770d4e0176d8426037ed6e0a2bd10c25db3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:59:14 +0800 Subject: [PATCH 20/54] Delete src/main/java/cod/ast/CoderiveParserBaseListener.java --- .../cod/ast/CoderiveParserBaseListener.java | 774 ------------------ 1 file changed, 774 deletions(-) delete mode 100644 src/main/java/cod/ast/CoderiveParserBaseListener.java diff --git a/src/main/java/cod/ast/CoderiveParserBaseListener.java b/src/main/java/cod/ast/CoderiveParserBaseListener.java deleted file mode 100644 index 10a9dadc..00000000 --- a/src/main/java/cod/ast/CoderiveParserBaseListener.java +++ /dev/null @@ -1,774 +0,0 @@ -// Generated from CoderiveParser.g4 by ANTLR 4.13.2 - -package cod.ast; - - -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.tree.ErrorNode; -import org.antlr.v4.runtime.tree.TerminalNode; - -/** - * This class provides an empty implementation of {@link CoderiveParserListener}, - * which can be extended to create a listener which only needs to handle a subset - * of the available methods. - */ -@SuppressWarnings("CheckReturnValue") -public class CoderiveParserBaseListener implements CoderiveParserListener { - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterProgram(CoderiveParser.ProgramContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitProgram(CoderiveParser.ProgramContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterUnitDeclaration(CoderiveParser.UnitDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitUnitDeclaration(CoderiveParser.UnitDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterQualifiedNameList(CoderiveParser.QualifiedNameListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitQualifiedNameList(CoderiveParser.QualifiedNameListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterQualifiedName(CoderiveParser.QualifiedNameContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitQualifiedName(CoderiveParser.QualifiedNameContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterTypeDeclaration(CoderiveParser.TypeDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitTypeDeclaration(CoderiveParser.TypeDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterModifiers(CoderiveParser.ModifiersContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitModifiers(CoderiveParser.ModifiersContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterTypeBody(CoderiveParser.TypeBodyContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitTypeBody(CoderiveParser.TypeBodyContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterFieldDeclaration(CoderiveParser.FieldDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitFieldDeclaration(CoderiveParser.FieldDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterConstructor(CoderiveParser.ConstructorContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitConstructor(CoderiveParser.ConstructorContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterMethodDeclaration(CoderiveParser.MethodDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitMethodDeclaration(CoderiveParser.MethodDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterIdList(CoderiveParser.IdListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitIdList(CoderiveParser.IdListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterSlotList(CoderiveParser.SlotListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitSlotList(CoderiveParser.SlotListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterParameterList(CoderiveParser.ParameterListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitParameterList(CoderiveParser.ParameterListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterParameter(CoderiveParser.ParameterContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitParameter(CoderiveParser.ParameterContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterType(CoderiveParser.TypeContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitType(CoderiveParser.TypeContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterSimpleType(CoderiveParser.SimpleTypeContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitSimpleType(CoderiveParser.SimpleTypeContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterStatement(CoderiveParser.StatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitStatement(CoderiveParser.StatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterVariableDeclaration(CoderiveParser.VariableDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitVariableDeclaration(CoderiveParser.VariableDeclarationContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterAssignment(CoderiveParser.AssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitAssignment(CoderiveParser.AssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterExpressionStatement(CoderiveParser.ExpressionStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitExpressionStatement(CoderiveParser.ExpressionStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterAssignable(CoderiveParser.AssignableContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitAssignable(CoderiveParser.AssignableContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterReturnSlotAssignment(CoderiveParser.ReturnSlotAssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitReturnSlotAssignment(CoderiveParser.ReturnSlotAssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterAssignableList(CoderiveParser.AssignableListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitAssignableList(CoderiveParser.AssignableListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterSlotMethodCallStatement(CoderiveParser.SlotMethodCallStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitSlotMethodCallStatement(CoderiveParser.SlotMethodCallStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterSlotMethodCall(CoderiveParser.SlotMethodCallContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitSlotMethodCall(CoderiveParser.SlotMethodCallContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterSlotCast(CoderiveParser.SlotCastContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitSlotCast(CoderiveParser.SlotCastContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterInputAssignment(CoderiveParser.InputAssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitInputAssignment(CoderiveParser.InputAssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterInputStatement(CoderiveParser.InputStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitInputStatement(CoderiveParser.InputStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterTypeInput(CoderiveParser.TypeInputContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitTypeInput(CoderiveParser.TypeInputContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterOutputStatement(CoderiveParser.OutputStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitOutputStatement(CoderiveParser.OutputStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterOutputSlotCall(CoderiveParser.OutputSlotCallContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitOutputSlotCall(CoderiveParser.OutputSlotCallContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterOutputNamedAssignment(CoderiveParser.OutputNamedAssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitOutputNamedAssignment(CoderiveParser.OutputNamedAssignmentContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterOutputExpression(CoderiveParser.OutputExpressionContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitOutputExpression(CoderiveParser.OutputExpressionContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterMethodCallStatement(CoderiveParser.MethodCallStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitMethodCallStatement(CoderiveParser.MethodCallStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterMethodCall(CoderiveParser.MethodCallContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitMethodCall(CoderiveParser.MethodCallContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterArgumentList(CoderiveParser.ArgumentListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitArgumentList(CoderiveParser.ArgumentListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterIfStatement(CoderiveParser.IfStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitIfStatement(CoderiveParser.IfStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterThenBlock(CoderiveParser.ThenBlockContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitThenBlock(CoderiveParser.ThenBlockContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterElseBlock(CoderiveParser.ElseBlockContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitElseBlock(CoderiveParser.ElseBlockContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterForStatement(CoderiveParser.ForStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitForStatement(CoderiveParser.ForStatementContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterOperatorStep(CoderiveParser.OperatorStepContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitOperatorStep(CoderiveParser.OperatorStepContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterRegularStep(CoderiveParser.RegularStepContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitRegularStep(CoderiveParser.RegularStepContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterMethodCallExpr(CoderiveParser.MethodCallExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitMethodCallExpr(CoderiveParser.MethodCallExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterUnaryExpr(CoderiveParser.UnaryExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitUnaryExpr(CoderiveParser.UnaryExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterPrimaryExpr(CoderiveParser.PrimaryExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitPrimaryExpr(CoderiveParser.PrimaryExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterComparisonExpr(CoderiveParser.ComparisonExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitComparisonExpr(CoderiveParser.ComparisonExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterTypeCastExpr(CoderiveParser.TypeCastExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitTypeCastExpr(CoderiveParser.TypeCastExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterAdditiveExpr(CoderiveParser.AdditiveExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitAdditiveExpr(CoderiveParser.AdditiveExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterMultiplicativeExpr(CoderiveParser.MultiplicativeExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitMultiplicativeExpr(CoderiveParser.MultiplicativeExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterIndexAccessExpr(CoderiveParser.IndexAccessExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitIndexAccessExpr(CoderiveParser.IndexAccessExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterIdentifierExpr(CoderiveParser.IdentifierExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitIdentifierExpr(CoderiveParser.IdentifierExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterIntLiteralExpr(CoderiveParser.IntLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitIntLiteralExpr(CoderiveParser.IntLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterFloatLiteralExpr(CoderiveParser.FloatLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitFloatLiteralExpr(CoderiveParser.FloatLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterStringLiteralExpr(CoderiveParser.StringLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitStringLiteralExpr(CoderiveParser.StringLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterBoolLiteralExpr(CoderiveParser.BoolLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitBoolLiteralExpr(CoderiveParser.BoolLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterParenthesizedExpr(CoderiveParser.ParenthesizedExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitParenthesizedExpr(CoderiveParser.ParenthesizedExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterArrayLiteralExpr(CoderiveParser.ArrayLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitArrayLiteralExpr(CoderiveParser.ArrayLiteralExprContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterArrayLiteral(CoderiveParser.ArrayLiteralContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitArrayLiteral(CoderiveParser.ArrayLiteralContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterExprList(CoderiveParser.ExprListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitExprList(CoderiveParser.ExprListContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterIndexAccess(CoderiveParser.IndexAccessContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitIndexAccess(CoderiveParser.IndexAccessContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterTypeCast(CoderiveParser.TypeCastContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitTypeCast(CoderiveParser.TypeCastContext ctx) { } - - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void enterEveryRule(ParserRuleContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void exitEveryRule(ParserRuleContext ctx) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void visitTerminal(TerminalNode node) { } - /** - * {@inheritDoc} - * - *

The default implementation does nothing.

- */ - @Override public void visitErrorNode(ErrorNode node) { } -} \ No newline at end of file From 6ef5608187581bb4d28610df4c86c1ff7c7a2c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:59:32 +0800 Subject: [PATCH 21/54] Delete src/main/java/cod/ast/CoderiveParser.java --- src/main/java/cod/ast/CoderiveParser.java | 4152 --------------------- 1 file changed, 4152 deletions(-) delete mode 100644 src/main/java/cod/ast/CoderiveParser.java diff --git a/src/main/java/cod/ast/CoderiveParser.java b/src/main/java/cod/ast/CoderiveParser.java deleted file mode 100644 index f76fc988..00000000 --- a/src/main/java/cod/ast/CoderiveParser.java +++ /dev/null @@ -1,4152 +0,0 @@ -// Generated from CoderiveParser.g4 by ANTLR 4.13.2 - -package cod.ast; - -import org.antlr.v4.runtime.atn.*; -import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.misc.*; -import org.antlr.v4.runtime.tree.*; -import java.util.List; -import java.util.Iterator; -import java.util.ArrayList; - -@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) -public class CoderiveParser extends Parser { - static { RuntimeMetaData.checkVersion("4.13.2", RuntimeMetaData.VERSION); } - - protected static final DFA[] _decisionToDFA; - protected static final PredictionContextCache _sharedContextCache = - new PredictionContextCache(); - public static final int - SHIP=1, LOCAL=2, UNIT=3, GET=4, EXTEND=5, THIS=6, VAR=7, OUTPUT=8, INPUT=9, - IF=10, ELSE=11, ELIF=12, FOR=13, BY=14, IN=15, TO=16, INT=17, STRING=18, - FLOAT=19, BOOL=20, INT_LIT=21, FLOAT_LIT=22, STRING_LIT=23, BOOL_LIT=24, - ID=25, ASSIGN=26, PLUS=27, MINUS=28, MUL=29, DIV=30, MOD=31, COLON=32, - GT=33, LT=34, GTE=35, LTE=36, EQ=37, NEQ=38, DOT=39, COMMA=40, LPAREN=41, - RPAREN=42, LBRACE=43, RBRACE=44, LBRACKET=45, RBRACKET=46, LINE_COMMENT=47, - BLOCK_COMMENT=48, WS=49; - public static final int - RULE_program = 0, RULE_unitDeclaration = 1, RULE_qualifiedNameList = 2, - RULE_qualifiedName = 3, RULE_typeDeclaration = 4, RULE_modifiers = 5, - RULE_typeBody = 6, RULE_fieldDeclaration = 7, RULE_constructor = 8, RULE_methodDeclaration = 9, - RULE_idList = 10, RULE_slotList = 11, RULE_parameterList = 12, RULE_parameter = 13, - RULE_type = 14, RULE_simpleType = 15, RULE_statement = 16, RULE_variableDeclaration = 17, - RULE_assignment = 18, RULE_expressionStatement = 19, RULE_assignable = 20, - RULE_returnSlotAssignment = 21, RULE_assignableList = 22, RULE_slotMethodCallStatement = 23, - RULE_slotMethodCall = 24, RULE_slotCast = 25, RULE_inputAssignment = 26, - RULE_inputStatement = 27, RULE_typeInput = 28, RULE_outputStatement = 29, - RULE_outputTarget = 30, RULE_methodCallStatement = 31, RULE_methodCall = 32, - RULE_argumentList = 33, RULE_ifStatement = 34, RULE_thenBlock = 35, RULE_elseBlock = 36, - RULE_forStatement = 37, RULE_forStepExpr = 38, RULE_expr = 39, RULE_primary = 40, - RULE_atom = 41, RULE_arrayLiteral = 42, RULE_exprList = 43, RULE_indexAccess = 44, - RULE_typeCast = 45; - private static String[] makeRuleNames() { - return new String[] { - "program", "unitDeclaration", "qualifiedNameList", "qualifiedName", "typeDeclaration", - "modifiers", "typeBody", "fieldDeclaration", "constructor", "methodDeclaration", - "idList", "slotList", "parameterList", "parameter", "type", "simpleType", - "statement", "variableDeclaration", "assignment", "expressionStatement", - "assignable", "returnSlotAssignment", "assignableList", "slotMethodCallStatement", - "slotMethodCall", "slotCast", "inputAssignment", "inputStatement", "typeInput", - "outputStatement", "outputTarget", "methodCallStatement", "methodCall", - "argumentList", "ifStatement", "thenBlock", "elseBlock", "forStatement", - "forStepExpr", "expr", "primary", "atom", "arrayLiteral", "exprList", - "indexAccess", "typeCast" - }; - } - public static final String[] ruleNames = makeRuleNames(); - - private static String[] makeLiteralNames() { - return new String[] { - null, "'ship'", "'local'", "'unit'", "'get'", "'extend'", "'this'", "'var'", - "'output'", "'input'", "'if'", "'else'", "'elif'", "'for'", "'by'", "'in'", - "'to'", "'int'", "'string'", "'float'", "'bool'", null, null, null, null, - null, "'='", "'+'", "'-'", "'*'", "'/'", "'%'", "':'", "'>'", "'<'", - "'>='", "'<='", "'=='", "'!='", "'.'", "','", "'('", "')'", "'{'", "'}'", - "'['", "']'" - }; - } - private static final String[] _LITERAL_NAMES = makeLiteralNames(); - private static String[] makeSymbolicNames() { - return new String[] { - null, "SHIP", "LOCAL", "UNIT", "GET", "EXTEND", "THIS", "VAR", "OUTPUT", - "INPUT", "IF", "ELSE", "ELIF", "FOR", "BY", "IN", "TO", "INT", "STRING", - "FLOAT", "BOOL", "INT_LIT", "FLOAT_LIT", "STRING_LIT", "BOOL_LIT", "ID", - "ASSIGN", "PLUS", "MINUS", "MUL", "DIV", "MOD", "COLON", "GT", "LT", - "GTE", "LTE", "EQ", "NEQ", "DOT", "COMMA", "LPAREN", "RPAREN", "LBRACE", - "RBRACE", "LBRACKET", "RBRACKET", "LINE_COMMENT", "BLOCK_COMMENT", "WS" - }; - } - private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); - public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); - - /** - * @deprecated Use {@link #VOCABULARY} instead. - */ - @Deprecated - public static final String[] tokenNames; - static { - tokenNames = new String[_SYMBOLIC_NAMES.length]; - for (int i = 0; i < tokenNames.length; i++) { - tokenNames[i] = VOCABULARY.getLiteralName(i); - if (tokenNames[i] == null) { - tokenNames[i] = VOCABULARY.getSymbolicName(i); - } - - if (tokenNames[i] == null) { - tokenNames[i] = ""; - } - } - } - - @Override - @Deprecated - public String[] getTokenNames() { - return tokenNames; - } - - @Override - - public Vocabulary getVocabulary() { - return VOCABULARY; - } - - @Override - public String getGrammarFileName() { return "CoderiveParser.g4"; } - - @Override - public String[] getRuleNames() { return ruleNames; } - - @Override - public String getSerializedATN() { return _serializedATN; } - - @Override - public ATN getATN() { return _ATN; } - - public CoderiveParser(TokenStream input) { - super(input); - _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); - } - - @SuppressWarnings("CheckReturnValue") - public static class ProgramContext extends ParserRuleContext { - public TerminalNode EOF() { return getToken(CoderiveParser.EOF, 0); } - public UnitDeclarationContext unitDeclaration() { - return getRuleContext(UnitDeclarationContext.class,0); - } - public List typeDeclaration() { - return getRuleContexts(TypeDeclarationContext.class); - } - public TypeDeclarationContext typeDeclaration(int i) { - return getRuleContext(TypeDeclarationContext.class,i); - } - public ProgramContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_program; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterProgram(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitProgram(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitProgram(this); - else return visitor.visitChildren(this); - } - } - - public final ProgramContext program() throws RecognitionException { - ProgramContext _localctx = new ProgramContext(_ctx, getState()); - enterRule(_localctx, 0, RULE_program); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(93); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==UNIT) { - { - setState(92); - unitDeclaration(); - } - } - - setState(98); - _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 33554438L) != 0)) { - { - { - setState(95); - typeDeclaration(); - } - } - setState(100); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(101); - match(EOF); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class UnitDeclarationContext extends ParserRuleContext { - public TerminalNode UNIT() { return getToken(CoderiveParser.UNIT, 0); } - public QualifiedNameContext qualifiedName() { - return getRuleContext(QualifiedNameContext.class,0); - } - public TerminalNode GET() { return getToken(CoderiveParser.GET, 0); } - public TerminalNode LBRACE() { return getToken(CoderiveParser.LBRACE, 0); } - public QualifiedNameListContext qualifiedNameList() { - return getRuleContext(QualifiedNameListContext.class,0); - } - public TerminalNode RBRACE() { return getToken(CoderiveParser.RBRACE, 0); } - public UnitDeclarationContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_unitDeclaration; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterUnitDeclaration(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitUnitDeclaration(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitUnitDeclaration(this); - else return visitor.visitChildren(this); - } - } - - public final UnitDeclarationContext unitDeclaration() throws RecognitionException { - UnitDeclarationContext _localctx = new UnitDeclarationContext(_ctx, getState()); - enterRule(_localctx, 2, RULE_unitDeclaration); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(103); - match(UNIT); - setState(104); - qualifiedName(); - setState(110); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==GET) { - { - setState(105); - match(GET); - setState(106); - match(LBRACE); - setState(107); - qualifiedNameList(); - setState(108); - match(RBRACE); - } - } - - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class QualifiedNameListContext extends ParserRuleContext { - public List qualifiedName() { - return getRuleContexts(QualifiedNameContext.class); - } - public QualifiedNameContext qualifiedName(int i) { - return getRuleContext(QualifiedNameContext.class,i); - } - public QualifiedNameListContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_qualifiedNameList; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterQualifiedNameList(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitQualifiedNameList(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitQualifiedNameList(this); - else return visitor.visitChildren(this); - } - } - - public final QualifiedNameListContext qualifiedNameList() throws RecognitionException { - QualifiedNameListContext _localctx = new QualifiedNameListContext(_ctx, getState()); - enterRule(_localctx, 4, RULE_qualifiedNameList); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(113); - _errHandler.sync(this); - _la = _input.LA(1); - do { - { - { - setState(112); - qualifiedName(); - } - } - setState(115); - _errHandler.sync(this); - _la = _input.LA(1); - } while ( _la==ID ); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class QualifiedNameContext extends ParserRuleContext { - public List ID() { return getTokens(CoderiveParser.ID); } - public TerminalNode ID(int i) { - return getToken(CoderiveParser.ID, i); - } - public List DOT() { return getTokens(CoderiveParser.DOT); } - public TerminalNode DOT(int i) { - return getToken(CoderiveParser.DOT, i); - } - public QualifiedNameContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_qualifiedName; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterQualifiedName(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitQualifiedName(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitQualifiedName(this); - else return visitor.visitChildren(this); - } - } - - public final QualifiedNameContext qualifiedName() throws RecognitionException { - QualifiedNameContext _localctx = new QualifiedNameContext(_ctx, getState()); - enterRule(_localctx, 6, RULE_qualifiedName); - try { - int _alt; - enterOuterAlt(_localctx, 1); - { - setState(117); - match(ID); - setState(122); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,4,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - { - { - setState(118); - match(DOT); - setState(119); - match(ID); - } - } - } - setState(124); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,4,_ctx); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class TypeDeclarationContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode LBRACE() { return getToken(CoderiveParser.LBRACE, 0); } - public TerminalNode RBRACE() { return getToken(CoderiveParser.RBRACE, 0); } - public ModifiersContext modifiers() { - return getRuleContext(ModifiersContext.class,0); - } - public TerminalNode EXTEND() { return getToken(CoderiveParser.EXTEND, 0); } - public QualifiedNameContext qualifiedName() { - return getRuleContext(QualifiedNameContext.class,0); - } - public List typeBody() { - return getRuleContexts(TypeBodyContext.class); - } - public TypeBodyContext typeBody(int i) { - return getRuleContext(TypeBodyContext.class,i); - } - public TypeDeclarationContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_typeDeclaration; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterTypeDeclaration(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitTypeDeclaration(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitTypeDeclaration(this); - else return visitor.visitChildren(this); - } - } - - public final TypeDeclarationContext typeDeclaration() throws RecognitionException { - TypeDeclarationContext _localctx = new TypeDeclarationContext(_ctx, getState()); - enterRule(_localctx, 8, RULE_typeDeclaration); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(126); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==SHIP || _la==LOCAL) { - { - setState(125); - modifiers(); - } - } - - setState(128); - match(ID); - setState(131); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==EXTEND) { - { - setState(129); - match(EXTEND); - setState(130); - qualifiedName(); - } - } - - setState(133); - match(LBRACE); - setState(137); - _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383864984966L) != 0)) { - { - { - setState(134); - typeBody(); - } - } - setState(139); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(140); - match(RBRACE); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ModifiersContext extends ParserRuleContext { - public TerminalNode SHIP() { return getToken(CoderiveParser.SHIP, 0); } - public TerminalNode LOCAL() { return getToken(CoderiveParser.LOCAL, 0); } - public ModifiersContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_modifiers; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterModifiers(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitModifiers(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitModifiers(this); - else return visitor.visitChildren(this); - } - } - - public final ModifiersContext modifiers() throws RecognitionException { - ModifiersContext _localctx = new ModifiersContext(_ctx, getState()); - enterRule(_localctx, 10, RULE_modifiers); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(142); - _la = _input.LA(1); - if ( !(_la==SHIP || _la==LOCAL) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class TypeBodyContext extends ParserRuleContext { - public FieldDeclarationContext fieldDeclaration() { - return getRuleContext(FieldDeclarationContext.class,0); - } - public ConstructorContext constructor() { - return getRuleContext(ConstructorContext.class,0); - } - public MethodDeclarationContext methodDeclaration() { - return getRuleContext(MethodDeclarationContext.class,0); - } - public StatementContext statement() { - return getRuleContext(StatementContext.class,0); - } - public TypeBodyContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_typeBody; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterTypeBody(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitTypeBody(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitTypeBody(this); - else return visitor.visitChildren(this); - } - } - - public final TypeBodyContext typeBody() throws RecognitionException { - TypeBodyContext _localctx = new TypeBodyContext(_ctx, getState()); - enterRule(_localctx, 12, RULE_typeBody); - try { - setState(148); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,8,_ctx) ) { - case 1: - enterOuterAlt(_localctx, 1); - { - setState(144); - fieldDeclaration(); - } - break; - case 2: - enterOuterAlt(_localctx, 2); - { - setState(145); - constructor(); - } - break; - case 3: - enterOuterAlt(_localctx, 3); - { - setState(146); - methodDeclaration(); - } - break; - case 4: - enterOuterAlt(_localctx, 4); - { - setState(147); - statement(); - } - break; - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class FieldDeclarationContext extends ParserRuleContext { - public TypeContext type() { - return getRuleContext(TypeContext.class,0); - } - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode ASSIGN() { return getToken(CoderiveParser.ASSIGN, 0); } - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public FieldDeclarationContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_fieldDeclaration; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterFieldDeclaration(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitFieldDeclaration(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitFieldDeclaration(this); - else return visitor.visitChildren(this); - } - } - - public final FieldDeclarationContext fieldDeclaration() throws RecognitionException { - FieldDeclarationContext _localctx = new FieldDeclarationContext(_ctx, getState()); - enterRule(_localctx, 14, RULE_fieldDeclaration); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(150); - type(); - setState(151); - match(ID); - setState(154); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==ASSIGN) { - { - setState(152); - match(ASSIGN); - setState(153); - expr(0); - } - } - - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ConstructorContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode LPAREN() { return getToken(CoderiveParser.LPAREN, 0); } - public TerminalNode RPAREN() { return getToken(CoderiveParser.RPAREN, 0); } - public TerminalNode LBRACE() { return getToken(CoderiveParser.LBRACE, 0); } - public TerminalNode RBRACE() { return getToken(CoderiveParser.RBRACE, 0); } - public ParameterListContext parameterList() { - return getRuleContext(ParameterListContext.class,0); - } - public List statement() { - return getRuleContexts(StatementContext.class); - } - public StatementContext statement(int i) { - return getRuleContext(StatementContext.class,i); - } - public ConstructorContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_constructor; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterConstructor(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitConstructor(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitConstructor(this); - else return visitor.visitChildren(this); - } - } - - public final ConstructorContext constructor() throws RecognitionException { - ConstructorContext _localctx = new ConstructorContext(_ctx, getState()); - enterRule(_localctx, 16, RULE_constructor); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(156); - match(ID); - setState(157); - match(LPAREN); - setState(159); - _errHandler.sync(this); - _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 35520512L) != 0)) { - { - setState(158); - parameterList(); - } - } - - setState(161); - match(RPAREN); - setState(162); - match(LBRACE); - setState(166); - _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383864984960L) != 0)) { - { - { - setState(163); - statement(); - } - } - setState(168); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(169); - match(RBRACE); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class MethodDeclarationContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode LPAREN() { return getToken(CoderiveParser.LPAREN, 0); } - public TerminalNode RPAREN() { return getToken(CoderiveParser.RPAREN, 0); } - public TerminalNode LBRACE() { return getToken(CoderiveParser.LBRACE, 0); } - public TerminalNode RBRACE() { return getToken(CoderiveParser.RBRACE, 0); } - public SlotListContext slotList() { - return getRuleContext(SlotListContext.class,0); - } - public ParameterListContext parameterList() { - return getRuleContext(ParameterListContext.class,0); - } - public List statement() { - return getRuleContexts(StatementContext.class); - } - public StatementContext statement(int i) { - return getRuleContext(StatementContext.class,i); - } - public ModifiersContext modifiers() { - return getRuleContext(ModifiersContext.class,0); - } - public MethodDeclarationContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_methodDeclaration; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterMethodDeclaration(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitMethodDeclaration(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitMethodDeclaration(this); - else return visitor.visitChildren(this); - } - } - - public final MethodDeclarationContext methodDeclaration() throws RecognitionException { - MethodDeclarationContext _localctx = new MethodDeclarationContext(_ctx, getState()); - enterRule(_localctx, 18, RULE_methodDeclaration); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(181); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) { - case 1: - { - setState(171); - slotList(); - setState(173); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==SHIP || _la==LOCAL) { - { - setState(172); - modifiers(); - } - } - - } - break; - case 2: - { - setState(176); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==SHIP || _la==LOCAL) { - { - setState(175); - modifiers(); - } - } - - setState(179); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==LBRACKET) { - { - setState(178); - slotList(); - } - } - - } - break; - } - setState(183); - match(ID); - setState(184); - match(LPAREN); - setState(186); - _errHandler.sync(this); - _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 35520512L) != 0)) { - { - setState(185); - parameterList(); - } - } - - setState(188); - match(RPAREN); - setState(189); - match(LBRACE); - setState(193); - _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383864984960L) != 0)) { - { - { - setState(190); - statement(); - } - } - setState(195); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(196); - match(RBRACE); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class IdListContext extends ParserRuleContext { - public List ID() { return getTokens(CoderiveParser.ID); } - public TerminalNode ID(int i) { - return getToken(CoderiveParser.ID, i); - } - public List COMMA() { return getTokens(CoderiveParser.COMMA); } - public TerminalNode COMMA(int i) { - return getToken(CoderiveParser.COMMA, i); - } - public IdListContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_idList; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterIdList(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitIdList(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitIdList(this); - else return visitor.visitChildren(this); - } - } - - public final IdListContext idList() throws RecognitionException { - IdListContext _localctx = new IdListContext(_ctx, getState()); - enterRule(_localctx, 20, RULE_idList); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(198); - match(ID); - setState(201); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,18,_ctx) ) { - case 1: - { - setState(199); - match(COMMA); - setState(200); - match(ID); - } - break; - } - setState(205); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==COMMA) { - { - setState(203); - match(COMMA); - setState(204); - match(ID); - } - } - - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class SlotListContext extends ParserRuleContext { - public TerminalNode LBRACKET() { return getToken(CoderiveParser.LBRACKET, 0); } - public IdListContext idList() { - return getRuleContext(IdListContext.class,0); - } - public TerminalNode RBRACKET() { return getToken(CoderiveParser.RBRACKET, 0); } - public SlotListContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_slotList; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterSlotList(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitSlotList(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitSlotList(this); - else return visitor.visitChildren(this); - } - } - - public final SlotListContext slotList() throws RecognitionException { - SlotListContext _localctx = new SlotListContext(_ctx, getState()); - enterRule(_localctx, 22, RULE_slotList); - try { - enterOuterAlt(_localctx, 1); - { - setState(207); - match(LBRACKET); - setState(208); - idList(); - setState(209); - match(RBRACKET); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ParameterListContext extends ParserRuleContext { - public List parameter() { - return getRuleContexts(ParameterContext.class); - } - public ParameterContext parameter(int i) { - return getRuleContext(ParameterContext.class,i); - } - public List COMMA() { return getTokens(CoderiveParser.COMMA); } - public TerminalNode COMMA(int i) { - return getToken(CoderiveParser.COMMA, i); - } - public ParameterListContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_parameterList; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterParameterList(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitParameterList(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitParameterList(this); - else return visitor.visitChildren(this); - } - } - - public final ParameterListContext parameterList() throws RecognitionException { - ParameterListContext _localctx = new ParameterListContext(_ctx, getState()); - enterRule(_localctx, 24, RULE_parameterList); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(211); - parameter(); - setState(216); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==COMMA) { - { - { - setState(212); - match(COMMA); - setState(213); - parameter(); - } - } - setState(218); - _errHandler.sync(this); - _la = _input.LA(1); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ParameterContext extends ParserRuleContext { - public TypeContext type() { - return getRuleContext(TypeContext.class,0); - } - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public ParameterContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_parameter; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterParameter(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitParameter(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitParameter(this); - else return visitor.visitChildren(this); - } - } - - public final ParameterContext parameter() throws RecognitionException { - ParameterContext _localctx = new ParameterContext(_ctx, getState()); - enterRule(_localctx, 26, RULE_parameter); - try { - enterOuterAlt(_localctx, 1); - { - setState(219); - type(); - setState(220); - match(ID); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class TypeContext extends ParserRuleContext { - public SimpleTypeContext simpleType() { - return getRuleContext(SimpleTypeContext.class,0); - } - public List LBRACKET() { return getTokens(CoderiveParser.LBRACKET); } - public TerminalNode LBRACKET(int i) { - return getToken(CoderiveParser.LBRACKET, i); - } - public List RBRACKET() { return getTokens(CoderiveParser.RBRACKET); } - public TerminalNode RBRACKET(int i) { - return getToken(CoderiveParser.RBRACKET, i); - } - public TypeContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_type; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterType(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitType(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitType(this); - else return visitor.visitChildren(this); - } - } - - public final TypeContext type() throws RecognitionException { - TypeContext _localctx = new TypeContext(_ctx, getState()); - enterRule(_localctx, 28, RULE_type); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(222); - simpleType(); - setState(227); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==LBRACKET) { - { - { - setState(223); - match(LBRACKET); - setState(224); - match(RBRACKET); - } - } - setState(229); - _errHandler.sync(this); - _la = _input.LA(1); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class SimpleTypeContext extends ParserRuleContext { - public TerminalNode INT() { return getToken(CoderiveParser.INT, 0); } - public TerminalNode STRING() { return getToken(CoderiveParser.STRING, 0); } - public TerminalNode FLOAT() { return getToken(CoderiveParser.FLOAT, 0); } - public TerminalNode BOOL() { return getToken(CoderiveParser.BOOL, 0); } - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public SimpleTypeContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_simpleType; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterSimpleType(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitSimpleType(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitSimpleType(this); - else return visitor.visitChildren(this); - } - } - - public final SimpleTypeContext simpleType() throws RecognitionException { - SimpleTypeContext _localctx = new SimpleTypeContext(_ctx, getState()); - enterRule(_localctx, 30, RULE_simpleType); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(230); - _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 35520512L) != 0)) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class StatementContext extends ParserRuleContext { - public VariableDeclarationContext variableDeclaration() { - return getRuleContext(VariableDeclarationContext.class,0); - } - public AssignmentContext assignment() { - return getRuleContext(AssignmentContext.class,0); - } - public ReturnSlotAssignmentContext returnSlotAssignment() { - return getRuleContext(ReturnSlotAssignmentContext.class,0); - } - public InputAssignmentContext inputAssignment() { - return getRuleContext(InputAssignmentContext.class,0); - } - public MethodCallStatementContext methodCallStatement() { - return getRuleContext(MethodCallStatementContext.class,0); - } - public OutputStatementContext outputStatement() { - return getRuleContext(OutputStatementContext.class,0); - } - public IfStatementContext ifStatement() { - return getRuleContext(IfStatementContext.class,0); - } - public ForStatementContext forStatement() { - return getRuleContext(ForStatementContext.class,0); - } - public ExpressionStatementContext expressionStatement() { - return getRuleContext(ExpressionStatementContext.class,0); - } - public SlotMethodCallStatementContext slotMethodCallStatement() { - return getRuleContext(SlotMethodCallStatementContext.class,0); - } - public StatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_statement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitStatement(this); - else return visitor.visitChildren(this); - } - } - - public final StatementContext statement() throws RecognitionException { - StatementContext _localctx = new StatementContext(_ctx, getState()); - enterRule(_localctx, 32, RULE_statement); - try { - setState(242); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,22,_ctx) ) { - case 1: - enterOuterAlt(_localctx, 1); - { - setState(232); - variableDeclaration(); - } - break; - case 2: - enterOuterAlt(_localctx, 2); - { - setState(233); - assignment(); - } - break; - case 3: - enterOuterAlt(_localctx, 3); - { - setState(234); - returnSlotAssignment(); - } - break; - case 4: - enterOuterAlt(_localctx, 4); - { - setState(235); - inputAssignment(); - } - break; - case 5: - enterOuterAlt(_localctx, 5); - { - setState(236); - methodCallStatement(); - } - break; - case 6: - enterOuterAlt(_localctx, 6); - { - setState(237); - outputStatement(); - } - break; - case 7: - enterOuterAlt(_localctx, 7); - { - setState(238); - ifStatement(); - } - break; - case 8: - enterOuterAlt(_localctx, 8); - { - setState(239); - forStatement(); - } - break; - case 9: - enterOuterAlt(_localctx, 9); - { - setState(240); - expressionStatement(); - } - break; - case 10: - enterOuterAlt(_localctx, 10); - { - setState(241); - slotMethodCallStatement(); - } - break; - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class VariableDeclarationContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode VAR() { return getToken(CoderiveParser.VAR, 0); } - public TypeContext type() { - return getRuleContext(TypeContext.class,0); - } - public TerminalNode ASSIGN() { return getToken(CoderiveParser.ASSIGN, 0); } - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public VariableDeclarationContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_variableDeclaration; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterVariableDeclaration(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitVariableDeclaration(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitVariableDeclaration(this); - else return visitor.visitChildren(this); - } - } - - public final VariableDeclarationContext variableDeclaration() throws RecognitionException { - VariableDeclarationContext _localctx = new VariableDeclarationContext(_ctx, getState()); - enterRule(_localctx, 34, RULE_variableDeclaration); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(246); - _errHandler.sync(this); - switch (_input.LA(1)) { - case VAR: - { - setState(244); - match(VAR); - } - break; - case INT: - case STRING: - case FLOAT: - case BOOL: - case ID: - { - setState(245); - type(); - } - break; - default: - throw new NoViableAltException(this); - } - setState(248); - match(ID); - setState(251); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==ASSIGN) { - { - setState(249); - match(ASSIGN); - setState(250); - expr(0); - } - } - - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class AssignmentContext extends ParserRuleContext { - public AssignableContext assignable() { - return getRuleContext(AssignableContext.class,0); - } - public TerminalNode ASSIGN() { return getToken(CoderiveParser.ASSIGN, 0); } - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public AssignmentContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_assignment; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterAssignment(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitAssignment(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitAssignment(this); - else return visitor.visitChildren(this); - } - } - - public final AssignmentContext assignment() throws RecognitionException { - AssignmentContext _localctx = new AssignmentContext(_ctx, getState()); - enterRule(_localctx, 36, RULE_assignment); - try { - enterOuterAlt(_localctx, 1); - { - setState(253); - assignable(); - setState(254); - match(ASSIGN); - setState(255); - expr(0); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ExpressionStatementContext extends ParserRuleContext { - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public ExpressionStatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_expressionStatement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterExpressionStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitExpressionStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitExpressionStatement(this); - else return visitor.visitChildren(this); - } - } - - public final ExpressionStatementContext expressionStatement() throws RecognitionException { - ExpressionStatementContext _localctx = new ExpressionStatementContext(_ctx, getState()); - enterRule(_localctx, 38, RULE_expressionStatement); - try { - enterOuterAlt(_localctx, 1); - { - setState(257); - expr(0); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class AssignableContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public IndexAccessContext indexAccess() { - return getRuleContext(IndexAccessContext.class,0); - } - public AssignableContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_assignable; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterAssignable(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitAssignable(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitAssignable(this); - else return visitor.visitChildren(this); - } - } - - public final AssignableContext assignable() throws RecognitionException { - AssignableContext _localctx = new AssignableContext(_ctx, getState()); - enterRule(_localctx, 40, RULE_assignable); - try { - setState(261); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,25,_ctx) ) { - case 1: - enterOuterAlt(_localctx, 1); - { - setState(259); - match(ID); - } - break; - case 2: - enterOuterAlt(_localctx, 2); - { - setState(260); - indexAccess(); - } - break; - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ReturnSlotAssignmentContext extends ParserRuleContext { - public AssignableListContext assignableList() { - return getRuleContext(AssignableListContext.class,0); - } - public TerminalNode ASSIGN() { return getToken(CoderiveParser.ASSIGN, 0); } - public SlotMethodCallContext slotMethodCall() { - return getRuleContext(SlotMethodCallContext.class,0); - } - public ReturnSlotAssignmentContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_returnSlotAssignment; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterReturnSlotAssignment(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitReturnSlotAssignment(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitReturnSlotAssignment(this); - else return visitor.visitChildren(this); - } - } - - public final ReturnSlotAssignmentContext returnSlotAssignment() throws RecognitionException { - ReturnSlotAssignmentContext _localctx = new ReturnSlotAssignmentContext(_ctx, getState()); - enterRule(_localctx, 42, RULE_returnSlotAssignment); - try { - enterOuterAlt(_localctx, 1); - { - setState(263); - assignableList(); - setState(264); - match(ASSIGN); - setState(265); - slotMethodCall(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class AssignableListContext extends ParserRuleContext { - public IdListContext idList() { - return getRuleContext(IdListContext.class,0); - } - public AssignableListContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_assignableList; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterAssignableList(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitAssignableList(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitAssignableList(this); - else return visitor.visitChildren(this); - } - } - - public final AssignableListContext assignableList() throws RecognitionException { - AssignableListContext _localctx = new AssignableListContext(_ctx, getState()); - enterRule(_localctx, 44, RULE_assignableList); - try { - enterOuterAlt(_localctx, 1); - { - setState(267); - idList(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class SlotMethodCallStatementContext extends ParserRuleContext { - public SlotMethodCallContext slotMethodCall() { - return getRuleContext(SlotMethodCallContext.class,0); - } - public SlotMethodCallStatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_slotMethodCallStatement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterSlotMethodCallStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitSlotMethodCallStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitSlotMethodCallStatement(this); - else return visitor.visitChildren(this); - } - } - - public final SlotMethodCallStatementContext slotMethodCallStatement() throws RecognitionException { - SlotMethodCallStatementContext _localctx = new SlotMethodCallStatementContext(_ctx, getState()); - enterRule(_localctx, 46, RULE_slotMethodCallStatement); - try { - enterOuterAlt(_localctx, 1); - { - setState(269); - slotMethodCall(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class SlotMethodCallContext extends ParserRuleContext { - public SlotCastContext slotCast() { - return getRuleContext(SlotCastContext.class,0); - } - public MethodCallContext methodCall() { - return getRuleContext(MethodCallContext.class,0); - } - public SlotMethodCallContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_slotMethodCall; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterSlotMethodCall(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitSlotMethodCall(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitSlotMethodCall(this); - else return visitor.visitChildren(this); - } - } - - public final SlotMethodCallContext slotMethodCall() throws RecognitionException { - SlotMethodCallContext _localctx = new SlotMethodCallContext(_ctx, getState()); - enterRule(_localctx, 48, RULE_slotMethodCall); - try { - enterOuterAlt(_localctx, 1); - { - setState(271); - slotCast(); - setState(272); - methodCall(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class SlotCastContext extends ParserRuleContext { - public TerminalNode LBRACKET() { return getToken(CoderiveParser.LBRACKET, 0); } - public IdListContext idList() { - return getRuleContext(IdListContext.class,0); - } - public TerminalNode RBRACKET() { return getToken(CoderiveParser.RBRACKET, 0); } - public TerminalNode COLON() { return getToken(CoderiveParser.COLON, 0); } - public SlotCastContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_slotCast; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterSlotCast(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitSlotCast(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitSlotCast(this); - else return visitor.visitChildren(this); - } - } - - public final SlotCastContext slotCast() throws RecognitionException { - SlotCastContext _localctx = new SlotCastContext(_ctx, getState()); - enterRule(_localctx, 50, RULE_slotCast); - try { - enterOuterAlt(_localctx, 1); - { - setState(274); - match(LBRACKET); - setState(275); - idList(); - setState(276); - match(RBRACKET); - setState(277); - match(COLON); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class InputAssignmentContext extends ParserRuleContext { - public AssignableContext assignable() { - return getRuleContext(AssignableContext.class,0); - } - public TerminalNode ASSIGN() { return getToken(CoderiveParser.ASSIGN, 0); } - public InputStatementContext inputStatement() { - return getRuleContext(InputStatementContext.class,0); - } - public InputAssignmentContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_inputAssignment; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterInputAssignment(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitInputAssignment(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitInputAssignment(this); - else return visitor.visitChildren(this); - } - } - - public final InputAssignmentContext inputAssignment() throws RecognitionException { - InputAssignmentContext _localctx = new InputAssignmentContext(_ctx, getState()); - enterRule(_localctx, 52, RULE_inputAssignment); - try { - enterOuterAlt(_localctx, 1); - { - setState(279); - assignable(); - setState(280); - match(ASSIGN); - setState(281); - inputStatement(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class InputStatementContext extends ParserRuleContext { - public TypeInputContext typeInput() { - return getRuleContext(TypeInputContext.class,0); - } - public TerminalNode INPUT() { return getToken(CoderiveParser.INPUT, 0); } - public InputStatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_inputStatement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterInputStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitInputStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitInputStatement(this); - else return visitor.visitChildren(this); - } - } - - public final InputStatementContext inputStatement() throws RecognitionException { - InputStatementContext _localctx = new InputStatementContext(_ctx, getState()); - enterRule(_localctx, 54, RULE_inputStatement); - try { - enterOuterAlt(_localctx, 1); - { - setState(283); - typeInput(); - setState(284); - match(INPUT); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class TypeInputContext extends ParserRuleContext { - public TerminalNode LPAREN() { return getToken(CoderiveParser.LPAREN, 0); } - public TypeContext type() { - return getRuleContext(TypeContext.class,0); - } - public TerminalNode RPAREN() { return getToken(CoderiveParser.RPAREN, 0); } - public TypeInputContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_typeInput; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterTypeInput(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitTypeInput(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitTypeInput(this); - else return visitor.visitChildren(this); - } - } - - public final TypeInputContext typeInput() throws RecognitionException { - TypeInputContext _localctx = new TypeInputContext(_ctx, getState()); - enterRule(_localctx, 56, RULE_typeInput); - try { - enterOuterAlt(_localctx, 1); - { - setState(286); - match(LPAREN); - setState(287); - type(); - setState(288); - match(RPAREN); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class OutputStatementContext extends ParserRuleContext { - public TerminalNode OUTPUT() { return getToken(CoderiveParser.OUTPUT, 0); } - public OutputTargetContext outputTarget() { - return getRuleContext(OutputTargetContext.class,0); - } - public OutputStatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_outputStatement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterOutputStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitOutputStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitOutputStatement(this); - else return visitor.visitChildren(this); - } - } - - public final OutputStatementContext outputStatement() throws RecognitionException { - OutputStatementContext _localctx = new OutputStatementContext(_ctx, getState()); - enterRule(_localctx, 58, RULE_outputStatement); - try { - enterOuterAlt(_localctx, 1); - { - setState(290); - match(OUTPUT); - setState(291); - outputTarget(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class OutputTargetContext extends ParserRuleContext { - public OutputTargetContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_outputTarget; } - - public OutputTargetContext() { } - public void copyFrom(OutputTargetContext ctx) { - super.copyFrom(ctx); - } - } - @SuppressWarnings("CheckReturnValue") - public static class OutputSlotCallContext extends OutputTargetContext { - public MethodCallContext methodCall() { - return getRuleContext(MethodCallContext.class,0); - } - public SlotCastContext slotCast() { - return getRuleContext(SlotCastContext.class,0); - } - public OutputSlotCallContext(OutputTargetContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterOutputSlotCall(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitOutputSlotCall(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitOutputSlotCall(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class OutputNamedAssignmentContext extends OutputTargetContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode ASSIGN() { return getToken(CoderiveParser.ASSIGN, 0); } - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public OutputNamedAssignmentContext(OutputTargetContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterOutputNamedAssignment(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitOutputNamedAssignment(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitOutputNamedAssignment(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class OutputExpressionContext extends OutputTargetContext { - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public OutputExpressionContext(OutputTargetContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterOutputExpression(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitOutputExpression(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitOutputExpression(this); - else return visitor.visitChildren(this); - } - } - - public final OutputTargetContext outputTarget() throws RecognitionException { - OutputTargetContext _localctx = new OutputTargetContext(_ctx, getState()); - enterRule(_localctx, 60, RULE_outputTarget); - int _la; - try { - setState(301); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) { - case 1: - _localctx = new OutputSlotCallContext(_localctx); - enterOuterAlt(_localctx, 1); - { - setState(294); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==LBRACKET) { - { - setState(293); - slotCast(); - } - } - - setState(296); - methodCall(); - } - break; - case 2: - _localctx = new OutputNamedAssignmentContext(_localctx); - enterOuterAlt(_localctx, 2); - { - setState(297); - match(ID); - setState(298); - match(ASSIGN); - setState(299); - expr(0); - } - break; - case 3: - _localctx = new OutputExpressionContext(_localctx); - enterOuterAlt(_localctx, 3); - { - setState(300); - expr(0); - } - break; - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class MethodCallStatementContext extends ParserRuleContext { - public MethodCallContext methodCall() { - return getRuleContext(MethodCallContext.class,0); - } - public MethodCallStatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_methodCallStatement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterMethodCallStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitMethodCallStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitMethodCallStatement(this); - else return visitor.visitChildren(this); - } - } - - public final MethodCallStatementContext methodCallStatement() throws RecognitionException { - MethodCallStatementContext _localctx = new MethodCallStatementContext(_ctx, getState()); - enterRule(_localctx, 62, RULE_methodCallStatement); - try { - enterOuterAlt(_localctx, 1); - { - setState(303); - methodCall(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class MethodCallContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode LPAREN() { return getToken(CoderiveParser.LPAREN, 0); } - public TerminalNode RPAREN() { return getToken(CoderiveParser.RPAREN, 0); } - public QualifiedNameContext qualifiedName() { - return getRuleContext(QualifiedNameContext.class,0); - } - public TerminalNode DOT() { return getToken(CoderiveParser.DOT, 0); } - public ArgumentListContext argumentList() { - return getRuleContext(ArgumentListContext.class,0); - } - public MethodCallContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_methodCall; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterMethodCall(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitMethodCall(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitMethodCall(this); - else return visitor.visitChildren(this); - } - } - - public final MethodCallContext methodCall() throws RecognitionException { - MethodCallContext _localctx = new MethodCallContext(_ctx, getState()); - enterRule(_localctx, 64, RULE_methodCall); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(308); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,28,_ctx) ) { - case 1: - { - setState(305); - qualifiedName(); - setState(306); - match(DOT); - } - break; - } - setState(310); - match(ID); - setState(311); - match(LPAREN); - setState(313); - _errHandler.sync(this); - _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383863009280L) != 0)) { - { - setState(312); - argumentList(); - } - } - - setState(315); - match(RPAREN); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ArgumentListContext extends ParserRuleContext { - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public List COMMA() { return getTokens(CoderiveParser.COMMA); } - public TerminalNode COMMA(int i) { - return getToken(CoderiveParser.COMMA, i); - } - public ArgumentListContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_argumentList; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterArgumentList(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitArgumentList(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitArgumentList(this); - else return visitor.visitChildren(this); - } - } - - public final ArgumentListContext argumentList() throws RecognitionException { - ArgumentListContext _localctx = new ArgumentListContext(_ctx, getState()); - enterRule(_localctx, 66, RULE_argumentList); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(317); - expr(0); - setState(322); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==COMMA) { - { - { - setState(318); - match(COMMA); - setState(319); - expr(0); - } - } - setState(324); - _errHandler.sync(this); - _la = _input.LA(1); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class IfStatementContext extends ParserRuleContext { - public TerminalNode IF() { return getToken(CoderiveParser.IF, 0); } - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public List thenBlock() { - return getRuleContexts(ThenBlockContext.class); - } - public ThenBlockContext thenBlock(int i) { - return getRuleContext(ThenBlockContext.class,i); - } - public List ELIF() { return getTokens(CoderiveParser.ELIF); } - public TerminalNode ELIF(int i) { - return getToken(CoderiveParser.ELIF, i); - } - public TerminalNode ELSE() { return getToken(CoderiveParser.ELSE, 0); } - public IfStatementContext ifStatement() { - return getRuleContext(IfStatementContext.class,0); - } - public ElseBlockContext elseBlock() { - return getRuleContext(ElseBlockContext.class,0); - } - public IfStatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_ifStatement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterIfStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitIfStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitIfStatement(this); - else return visitor.visitChildren(this); - } - } - - public final IfStatementContext ifStatement() throws RecognitionException { - IfStatementContext _localctx = new IfStatementContext(_ctx, getState()); - enterRule(_localctx, 68, RULE_ifStatement); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(325); - match(IF); - setState(326); - expr(0); - setState(327); - thenBlock(); - setState(334); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==ELIF) { - { - { - setState(328); - match(ELIF); - setState(329); - expr(0); - setState(330); - thenBlock(); - } - } - setState(336); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(342); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==ELSE) { - { - setState(337); - match(ELSE); - setState(340); - _errHandler.sync(this); - switch (_input.LA(1)) { - case IF: - { - setState(338); - ifStatement(); - } - break; - case LBRACE: - { - setState(339); - elseBlock(); - } - break; - default: - throw new NoViableAltException(this); - } - } - } - - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ThenBlockContext extends ParserRuleContext { - public TerminalNode LBRACE() { return getToken(CoderiveParser.LBRACE, 0); } - public TerminalNode RBRACE() { return getToken(CoderiveParser.RBRACE, 0); } - public List statement() { - return getRuleContexts(StatementContext.class); - } - public StatementContext statement(int i) { - return getRuleContext(StatementContext.class,i); - } - public ThenBlockContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_thenBlock; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterThenBlock(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitThenBlock(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitThenBlock(this); - else return visitor.visitChildren(this); - } - } - - public final ThenBlockContext thenBlock() throws RecognitionException { - ThenBlockContext _localctx = new ThenBlockContext(_ctx, getState()); - enterRule(_localctx, 70, RULE_thenBlock); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(344); - match(LBRACE); - setState(348); - _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383864984960L) != 0)) { - { - { - setState(345); - statement(); - } - } - setState(350); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(351); - match(RBRACE); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ElseBlockContext extends ParserRuleContext { - public TerminalNode LBRACE() { return getToken(CoderiveParser.LBRACE, 0); } - public TerminalNode RBRACE() { return getToken(CoderiveParser.RBRACE, 0); } - public List statement() { - return getRuleContexts(StatementContext.class); - } - public StatementContext statement(int i) { - return getRuleContext(StatementContext.class,i); - } - public ElseBlockContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_elseBlock; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterElseBlock(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitElseBlock(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitElseBlock(this); - else return visitor.visitChildren(this); - } - } - - public final ElseBlockContext elseBlock() throws RecognitionException { - ElseBlockContext _localctx = new ElseBlockContext(_ctx, getState()); - enterRule(_localctx, 72, RULE_elseBlock); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(353); - match(LBRACE); - setState(357); - _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383864984960L) != 0)) { - { - { - setState(354); - statement(); - } - } - setState(359); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(360); - match(RBRACE); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ForStatementContext extends ParserRuleContext { - public TerminalNode FOR() { return getToken(CoderiveParser.FOR, 0); } - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public TerminalNode IN() { return getToken(CoderiveParser.IN, 0); } - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public TerminalNode TO() { return getToken(CoderiveParser.TO, 0); } - public TerminalNode LBRACE() { return getToken(CoderiveParser.LBRACE, 0); } - public TerminalNode RBRACE() { return getToken(CoderiveParser.RBRACE, 0); } - public TerminalNode BY() { return getToken(CoderiveParser.BY, 0); } - public ForStepExprContext forStepExpr() { - return getRuleContext(ForStepExprContext.class,0); - } - public List statement() { - return getRuleContexts(StatementContext.class); - } - public StatementContext statement(int i) { - return getRuleContext(StatementContext.class,i); - } - public ForStatementContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_forStatement; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterForStatement(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitForStatement(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitForStatement(this); - else return visitor.visitChildren(this); - } - } - - public final ForStatementContext forStatement() throws RecognitionException { - ForStatementContext _localctx = new ForStatementContext(_ctx, getState()); - enterRule(_localctx, 74, RULE_forStatement); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(362); - match(FOR); - setState(363); - match(ID); - setState(366); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==BY) { - { - setState(364); - match(BY); - setState(365); - forStepExpr(); - } - } - - setState(368); - match(IN); - setState(369); - expr(0); - setState(370); - match(TO); - setState(371); - expr(0); - setState(372); - match(LBRACE); - setState(376); - _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383864984960L) != 0)) { - { - { - setState(373); - statement(); - } - } - setState(378); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(379); - match(RBRACE); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ForStepExprContext extends ParserRuleContext { - public ForStepExprContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_forStepExpr; } - - public ForStepExprContext() { } - public void copyFrom(ForStepExprContext ctx) { - super.copyFrom(ctx); - } - } - @SuppressWarnings("CheckReturnValue") - public static class RegularStepContext extends ForStepExprContext { - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public RegularStepContext(ForStepExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterRegularStep(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitRegularStep(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitRegularStep(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class OperatorStepContext extends ForStepExprContext { - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public TerminalNode MUL() { return getToken(CoderiveParser.MUL, 0); } - public TerminalNode DIV() { return getToken(CoderiveParser.DIV, 0); } - public TerminalNode PLUS() { return getToken(CoderiveParser.PLUS, 0); } - public TerminalNode MINUS() { return getToken(CoderiveParser.MINUS, 0); } - public OperatorStepContext(ForStepExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterOperatorStep(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitOperatorStep(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitOperatorStep(this); - else return visitor.visitChildren(this); - } - } - - public final ForStepExprContext forStepExpr() throws RecognitionException { - ForStepExprContext _localctx = new ForStepExprContext(_ctx, getState()); - enterRule(_localctx, 76, RULE_forStepExpr); - int _la; - try { - setState(384); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,38,_ctx) ) { - case 1: - _localctx = new OperatorStepContext(_localctx); - enterOuterAlt(_localctx, 1); - { - setState(381); - _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 2013265920L) != 0)) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - setState(382); - expr(0); - } - break; - case 2: - _localctx = new RegularStepContext(_localctx); - enterOuterAlt(_localctx, 2); - { - setState(383); - expr(0); - } - break; - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ExprContext extends ParserRuleContext { - public ExprContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_expr; } - - public ExprContext() { } - public void copyFrom(ExprContext ctx) { - super.copyFrom(ctx); - } - } - @SuppressWarnings("CheckReturnValue") - public static class MethodCallExprContext extends ExprContext { - public MethodCallContext methodCall() { - return getRuleContext(MethodCallContext.class,0); - } - public MethodCallExprContext(ExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterMethodCallExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitMethodCallExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitMethodCallExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class UnaryExprContext extends ExprContext { - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public TerminalNode PLUS() { return getToken(CoderiveParser.PLUS, 0); } - public TerminalNode MINUS() { return getToken(CoderiveParser.MINUS, 0); } - public UnaryExprContext(ExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterUnaryExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitUnaryExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitUnaryExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class PrimaryExprContext extends ExprContext { - public PrimaryContext primary() { - return getRuleContext(PrimaryContext.class,0); - } - public PrimaryExprContext(ExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterPrimaryExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitPrimaryExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitPrimaryExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class ComparisonExprContext extends ExprContext { - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public TerminalNode GT() { return getToken(CoderiveParser.GT, 0); } - public TerminalNode LT() { return getToken(CoderiveParser.LT, 0); } - public TerminalNode GTE() { return getToken(CoderiveParser.GTE, 0); } - public TerminalNode LTE() { return getToken(CoderiveParser.LTE, 0); } - public TerminalNode EQ() { return getToken(CoderiveParser.EQ, 0); } - public TerminalNode NEQ() { return getToken(CoderiveParser.NEQ, 0); } - public ComparisonExprContext(ExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterComparisonExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitComparisonExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitComparisonExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class TypeCastExprContext extends ExprContext { - public TypeCastContext typeCast() { - return getRuleContext(TypeCastContext.class,0); - } - public TypeCastExprContext(ExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterTypeCastExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitTypeCastExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitTypeCastExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class AdditiveExprContext extends ExprContext { - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public TerminalNode PLUS() { return getToken(CoderiveParser.PLUS, 0); } - public TerminalNode MINUS() { return getToken(CoderiveParser.MINUS, 0); } - public AdditiveExprContext(ExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterAdditiveExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitAdditiveExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitAdditiveExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class MultiplicativeExprContext extends ExprContext { - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public TerminalNode MUL() { return getToken(CoderiveParser.MUL, 0); } - public TerminalNode DIV() { return getToken(CoderiveParser.DIV, 0); } - public TerminalNode MOD() { return getToken(CoderiveParser.MOD, 0); } - public MultiplicativeExprContext(ExprContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterMultiplicativeExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitMultiplicativeExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitMultiplicativeExpr(this); - else return visitor.visitChildren(this); - } - } - - public final ExprContext expr() throws RecognitionException { - return expr(0); - } - - private ExprContext expr(int _p) throws RecognitionException { - ParserRuleContext _parentctx = _ctx; - int _parentState = getState(); - ExprContext _localctx = new ExprContext(_ctx, _parentState); - ExprContext _prevctx = _localctx; - int _startState = 78; - enterRecursionRule(_localctx, 78, RULE_expr, _p); - int _la; - try { - int _alt; - enterOuterAlt(_localctx, 1); - { - setState(392); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,39,_ctx) ) { - case 1: - { - _localctx = new UnaryExprContext(_localctx); - _ctx = _localctx; - _prevctx = _localctx; - - setState(387); - _la = _input.LA(1); - if ( !(_la==PLUS || _la==MINUS) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - setState(388); - expr(7); - } - break; - case 2: - { - _localctx = new PrimaryExprContext(_localctx); - _ctx = _localctx; - _prevctx = _localctx; - setState(389); - primary(); - } - break; - case 3: - { - _localctx = new MethodCallExprContext(_localctx); - _ctx = _localctx; - _prevctx = _localctx; - setState(390); - methodCall(); - } - break; - case 4: - { - _localctx = new TypeCastExprContext(_localctx); - _ctx = _localctx; - _prevctx = _localctx; - setState(391); - typeCast(); - } - break; - } - _ctx.stop = _input.LT(-1); - setState(405); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,41,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - if ( _parseListeners!=null ) triggerExitRuleEvent(); - _prevctx = _localctx; - { - setState(403); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,40,_ctx) ) { - case 1: - { - _localctx = new MultiplicativeExprContext(new ExprContext(_parentctx, _parentState)); - pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(394); - if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)"); - setState(395); - _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 3758096384L) != 0)) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - setState(396); - expr(7); - } - break; - case 2: - { - _localctx = new AdditiveExprContext(new ExprContext(_parentctx, _parentState)); - pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(397); - if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); - setState(398); - _la = _input.LA(1); - if ( !(_la==PLUS || _la==MINUS) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - setState(399); - expr(6); - } - break; - case 3: - { - _localctx = new ComparisonExprContext(new ExprContext(_parentctx, _parentState)); - pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(400); - if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); - setState(401); - _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 541165879296L) != 0)) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - setState(402); - expr(5); - } - break; - } - } - } - setState(407); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,41,_ctx); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - unrollRecursionContexts(_parentctx); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class PrimaryContext extends ParserRuleContext { - public PrimaryContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_primary; } - - public PrimaryContext() { } - public void copyFrom(PrimaryContext ctx) { - super.copyFrom(ctx); - } - } - @SuppressWarnings("CheckReturnValue") - public static class IndexAccessExprContext extends PrimaryContext { - public AtomContext atom() { - return getRuleContext(AtomContext.class,0); - } - public List LBRACKET() { return getTokens(CoderiveParser.LBRACKET); } - public TerminalNode LBRACKET(int i) { - return getToken(CoderiveParser.LBRACKET, i); - } - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public List RBRACKET() { return getTokens(CoderiveParser.RBRACKET); } - public TerminalNode RBRACKET(int i) { - return getToken(CoderiveParser.RBRACKET, i); - } - public IndexAccessExprContext(PrimaryContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterIndexAccessExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitIndexAccessExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitIndexAccessExpr(this); - else return visitor.visitChildren(this); - } - } - - public final PrimaryContext primary() throws RecognitionException { - PrimaryContext _localctx = new PrimaryContext(_ctx, getState()); - enterRule(_localctx, 80, RULE_primary); - try { - int _alt; - _localctx = new IndexAccessExprContext(_localctx); - enterOuterAlt(_localctx, 1); - { - setState(408); - atom(); - setState(415); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,42,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - { - { - setState(409); - match(LBRACKET); - setState(410); - expr(0); - setState(411); - match(RBRACKET); - } - } - } - setState(417); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,42,_ctx); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class AtomContext extends ParserRuleContext { - public AtomContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_atom; } - - public AtomContext() { } - public void copyFrom(AtomContext ctx) { - super.copyFrom(ctx); - } - } - @SuppressWarnings("CheckReturnValue") - public static class FloatLiteralExprContext extends AtomContext { - public TerminalNode FLOAT_LIT() { return getToken(CoderiveParser.FLOAT_LIT, 0); } - public FloatLiteralExprContext(AtomContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterFloatLiteralExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitFloatLiteralExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitFloatLiteralExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class StringLiteralExprContext extends AtomContext { - public TerminalNode STRING_LIT() { return getToken(CoderiveParser.STRING_LIT, 0); } - public StringLiteralExprContext(AtomContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterStringLiteralExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitStringLiteralExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitStringLiteralExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class IntLiteralExprContext extends AtomContext { - public TerminalNode INT_LIT() { return getToken(CoderiveParser.INT_LIT, 0); } - public IntLiteralExprContext(AtomContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterIntLiteralExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitIntLiteralExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitIntLiteralExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class ParenthesizedExprContext extends AtomContext { - public TerminalNode LPAREN() { return getToken(CoderiveParser.LPAREN, 0); } - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public TerminalNode RPAREN() { return getToken(CoderiveParser.RPAREN, 0); } - public ParenthesizedExprContext(AtomContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterParenthesizedExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitParenthesizedExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitParenthesizedExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class ArrayLiteralExprContext extends AtomContext { - public ArrayLiteralContext arrayLiteral() { - return getRuleContext(ArrayLiteralContext.class,0); - } - public ArrayLiteralExprContext(AtomContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterArrayLiteralExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitArrayLiteralExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitArrayLiteralExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class BoolLiteralExprContext extends AtomContext { - public TerminalNode BOOL_LIT() { return getToken(CoderiveParser.BOOL_LIT, 0); } - public BoolLiteralExprContext(AtomContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterBoolLiteralExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitBoolLiteralExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitBoolLiteralExpr(this); - else return visitor.visitChildren(this); - } - } - @SuppressWarnings("CheckReturnValue") - public static class IdentifierExprContext extends AtomContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public IdentifierExprContext(AtomContext ctx) { copyFrom(ctx); } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterIdentifierExpr(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitIdentifierExpr(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitIdentifierExpr(this); - else return visitor.visitChildren(this); - } - } - - public final AtomContext atom() throws RecognitionException { - AtomContext _localctx = new AtomContext(_ctx, getState()); - enterRule(_localctx, 82, RULE_atom); - try { - setState(428); - _errHandler.sync(this); - switch (_input.LA(1)) { - case ID: - _localctx = new IdentifierExprContext(_localctx); - enterOuterAlt(_localctx, 1); - { - setState(418); - match(ID); - } - break; - case INT_LIT: - _localctx = new IntLiteralExprContext(_localctx); - enterOuterAlt(_localctx, 2); - { - setState(419); - match(INT_LIT); - } - break; - case FLOAT_LIT: - _localctx = new FloatLiteralExprContext(_localctx); - enterOuterAlt(_localctx, 3); - { - setState(420); - match(FLOAT_LIT); - } - break; - case STRING_LIT: - _localctx = new StringLiteralExprContext(_localctx); - enterOuterAlt(_localctx, 4); - { - setState(421); - match(STRING_LIT); - } - break; - case BOOL_LIT: - _localctx = new BoolLiteralExprContext(_localctx); - enterOuterAlt(_localctx, 5); - { - setState(422); - match(BOOL_LIT); - } - break; - case LPAREN: - _localctx = new ParenthesizedExprContext(_localctx); - enterOuterAlt(_localctx, 6); - { - setState(423); - match(LPAREN); - setState(424); - expr(0); - setState(425); - match(RPAREN); - } - break; - case LBRACKET: - _localctx = new ArrayLiteralExprContext(_localctx); - enterOuterAlt(_localctx, 7); - { - setState(427); - arrayLiteral(); - } - break; - default: - throw new NoViableAltException(this); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ArrayLiteralContext extends ParserRuleContext { - public TerminalNode LBRACKET() { return getToken(CoderiveParser.LBRACKET, 0); } - public TerminalNode RBRACKET() { return getToken(CoderiveParser.RBRACKET, 0); } - public ExprListContext exprList() { - return getRuleContext(ExprListContext.class,0); - } - public ArrayLiteralContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_arrayLiteral; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterArrayLiteral(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitArrayLiteral(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitArrayLiteral(this); - else return visitor.visitChildren(this); - } - } - - public final ArrayLiteralContext arrayLiteral() throws RecognitionException { - ArrayLiteralContext _localctx = new ArrayLiteralContext(_ctx, getState()); - enterRule(_localctx, 84, RULE_arrayLiteral); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(430); - match(LBRACKET); - setState(432); - _errHandler.sync(this); - _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 37383863009280L) != 0)) { - { - setState(431); - exprList(); - } - } - - setState(434); - match(RBRACKET); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ExprListContext extends ParserRuleContext { - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public List COMMA() { return getTokens(CoderiveParser.COMMA); } - public TerminalNode COMMA(int i) { - return getToken(CoderiveParser.COMMA, i); - } - public ExprListContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_exprList; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterExprList(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitExprList(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitExprList(this); - else return visitor.visitChildren(this); - } - } - - public final ExprListContext exprList() throws RecognitionException { - ExprListContext _localctx = new ExprListContext(_ctx, getState()); - enterRule(_localctx, 86, RULE_exprList); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(436); - expr(0); - setState(441); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==COMMA) { - { - { - setState(437); - match(COMMA); - setState(438); - expr(0); - } - } - setState(443); - _errHandler.sync(this); - _la = _input.LA(1); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class IndexAccessContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(CoderiveParser.ID, 0); } - public List LBRACKET() { return getTokens(CoderiveParser.LBRACKET); } - public TerminalNode LBRACKET(int i) { - return getToken(CoderiveParser.LBRACKET, i); - } - public List expr() { - return getRuleContexts(ExprContext.class); - } - public ExprContext expr(int i) { - return getRuleContext(ExprContext.class,i); - } - public List RBRACKET() { return getTokens(CoderiveParser.RBRACKET); } - public TerminalNode RBRACKET(int i) { - return getToken(CoderiveParser.RBRACKET, i); - } - public IndexAccessContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_indexAccess; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterIndexAccess(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitIndexAccess(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitIndexAccess(this); - else return visitor.visitChildren(this); - } - } - - public final IndexAccessContext indexAccess() throws RecognitionException { - IndexAccessContext _localctx = new IndexAccessContext(_ctx, getState()); - enterRule(_localctx, 88, RULE_indexAccess); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(444); - match(ID); - setState(449); - _errHandler.sync(this); - _la = _input.LA(1); - do { - { - { - setState(445); - match(LBRACKET); - setState(446); - expr(0); - setState(447); - match(RBRACKET); - } - } - setState(451); - _errHandler.sync(this); - _la = _input.LA(1); - } while ( _la==LBRACKET ); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class TypeCastContext extends ParserRuleContext { - public TerminalNode LPAREN() { return getToken(CoderiveParser.LPAREN, 0); } - public TypeContext type() { - return getRuleContext(TypeContext.class,0); - } - public TerminalNode RPAREN() { return getToken(CoderiveParser.RPAREN, 0); } - public ExprContext expr() { - return getRuleContext(ExprContext.class,0); - } - public TypeCastContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_typeCast; } - @Override - public void enterRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).enterTypeCast(this); - } - @Override - public void exitRule(ParseTreeListener listener) { - if ( listener instanceof CoderiveParserListener ) ((CoderiveParserListener)listener).exitTypeCast(this); - } - @Override - public T accept(ParseTreeVisitor visitor) { - if ( visitor instanceof CoderiveParserVisitor ) return ((CoderiveParserVisitor)visitor).visitTypeCast(this); - else return visitor.visitChildren(this); - } - } - - public final TypeCastContext typeCast() throws RecognitionException { - TypeCastContext _localctx = new TypeCastContext(_ctx, getState()); - enterRule(_localctx, 90, RULE_typeCast); - try { - enterOuterAlt(_localctx, 1); - { - setState(453); - match(LPAREN); - setState(454); - type(); - setState(455); - match(RPAREN); - setState(456); - expr(0); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { - switch (ruleIndex) { - case 39: - return expr_sempred((ExprContext)_localctx, predIndex); - } - return true; - } - private boolean expr_sempred(ExprContext _localctx, int predIndex) { - switch (predIndex) { - case 0: - return precpred(_ctx, 6); - case 1: - return precpred(_ctx, 5); - case 2: - return precpred(_ctx, 4); - } - return true; - } - - public static final String _serializedATN = - "\u0004\u00011\u01cb\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ - "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ - "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ - "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ - "\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002\u000f\u0007\u000f"+ - "\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002\u0012\u0007\u0012"+ - "\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002\u0015\u0007\u0015"+ - "\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002\u0018\u0007\u0018"+ - "\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002\u001b\u0007\u001b"+ - "\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002\u001e\u0007\u001e"+ - "\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007!\u0002\"\u0007\"\u0002"+ - "#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007&\u0002\'\u0007\'\u0002"+ - "(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007+\u0002,\u0007,\u0002"+ - "-\u0007-\u0001\u0000\u0003\u0000^\b\u0000\u0001\u0000\u0005\u0000a\b\u0000"+ - "\n\u0000\f\u0000d\t\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003\u0001"+ - "o\b\u0001\u0001\u0002\u0004\u0002r\b\u0002\u000b\u0002\f\u0002s\u0001"+ - "\u0003\u0001\u0003\u0001\u0003\u0005\u0003y\b\u0003\n\u0003\f\u0003|\t"+ - "\u0003\u0001\u0004\u0003\u0004\u007f\b\u0004\u0001\u0004\u0001\u0004\u0001"+ - "\u0004\u0003\u0004\u0084\b\u0004\u0001\u0004\u0001\u0004\u0005\u0004\u0088"+ - "\b\u0004\n\u0004\f\u0004\u008b\t\u0004\u0001\u0004\u0001\u0004\u0001\u0005"+ - "\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006"+ - "\u0095\b\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0003\u0007"+ - "\u009b\b\u0007\u0001\b\u0001\b\u0001\b\u0003\b\u00a0\b\b\u0001\b\u0001"+ - "\b\u0001\b\u0005\b\u00a5\b\b\n\b\f\b\u00a8\t\b\u0001\b\u0001\b\u0001\t"+ - "\u0001\t\u0003\t\u00ae\b\t\u0001\t\u0003\t\u00b1\b\t\u0001\t\u0003\t\u00b4"+ - "\b\t\u0003\t\u00b6\b\t\u0001\t\u0001\t\u0001\t\u0003\t\u00bb\b\t\u0001"+ - "\t\u0001\t\u0001\t\u0005\t\u00c0\b\t\n\t\f\t\u00c3\t\t\u0001\t\u0001\t"+ - "\u0001\n\u0001\n\u0001\n\u0003\n\u00ca\b\n\u0001\n\u0001\n\u0003\n\u00ce"+ - "\b\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001"+ - "\f\u0005\f\u00d7\b\f\n\f\f\f\u00da\t\f\u0001\r\u0001\r\u0001\r\u0001\u000e"+ - "\u0001\u000e\u0001\u000e\u0005\u000e\u00e2\b\u000e\n\u000e\f\u000e\u00e5"+ - "\t\u000e\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ - "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ - "\u0010\u0003\u0010\u00f3\b\u0010\u0001\u0011\u0001\u0011\u0003\u0011\u00f7"+ - "\b\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0003\u0011\u00fc\b\u0011"+ - "\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013"+ - "\u0001\u0014\u0001\u0014\u0003\u0014\u0106\b\u0014\u0001\u0015\u0001\u0015"+ - "\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ - "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019"+ - "\u0001\u0019\u0001\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+ - "\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c"+ - "\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001e\u0003\u001e"+ - "\u0127\b\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e"+ - "\u0003\u001e\u012e\b\u001e\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001"+ - " \u0003 \u0135\b \u0001 \u0001 \u0001 \u0003 \u013a\b \u0001 \u0001 \u0001"+ - "!\u0001!\u0001!\u0005!\u0141\b!\n!\f!\u0144\t!\u0001\"\u0001\"\u0001\""+ - "\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u014d\b\"\n\"\f\"\u0150\t\"\u0001"+ - "\"\u0001\"\u0001\"\u0003\"\u0155\b\"\u0003\"\u0157\b\"\u0001#\u0001#\u0005"+ - "#\u015b\b#\n#\f#\u015e\t#\u0001#\u0001#\u0001$\u0001$\u0005$\u0164\b$"+ - "\n$\f$\u0167\t$\u0001$\u0001$\u0001%\u0001%\u0001%\u0001%\u0003%\u016f"+ - "\b%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0005%\u0177\b%\n%\f%\u017a"+ - "\t%\u0001%\u0001%\u0001&\u0001&\u0001&\u0003&\u0181\b&\u0001\'\u0001\'"+ - "\u0001\'\u0001\'\u0001\'\u0001\'\u0003\'\u0189\b\'\u0001\'\u0001\'\u0001"+ - "\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0005\'\u0194\b\'\n"+ - "\'\f\'\u0197\t\'\u0001(\u0001(\u0001(\u0001(\u0001(\u0005(\u019e\b(\n"+ - "(\f(\u01a1\t(\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)"+ - "\u0001)\u0001)\u0003)\u01ad\b)\u0001*\u0001*\u0003*\u01b1\b*\u0001*\u0001"+ - "*\u0001+\u0001+\u0001+\u0005+\u01b8\b+\n+\f+\u01bb\t+\u0001,\u0001,\u0001"+ - ",\u0001,\u0001,\u0004,\u01c2\b,\u000b,\f,\u01c3\u0001-\u0001-\u0001-\u0001"+ - "-\u0001-\u0001-\u0000\u0001N.\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010"+ - "\u0012\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,.02468:<>@BDFHJLNPR"+ - "TVXZ\u0000\u0006\u0001\u0000\u0001\u0002\u0002\u0000\u0011\u0014\u0019"+ - "\u0019\u0001\u0000\u001b\u001e\u0001\u0000\u001b\u001c\u0001\u0000\u001d"+ - "\u001f\u0001\u0000!&\u01de\u0000]\u0001\u0000\u0000\u0000\u0002g\u0001"+ - "\u0000\u0000\u0000\u0004q\u0001\u0000\u0000\u0000\u0006u\u0001\u0000\u0000"+ - "\u0000\b~\u0001\u0000\u0000\u0000\n\u008e\u0001\u0000\u0000\u0000\f\u0094"+ - "\u0001\u0000\u0000\u0000\u000e\u0096\u0001\u0000\u0000\u0000\u0010\u009c"+ - "\u0001\u0000\u0000\u0000\u0012\u00b5\u0001\u0000\u0000\u0000\u0014\u00c6"+ - "\u0001\u0000\u0000\u0000\u0016\u00cf\u0001\u0000\u0000\u0000\u0018\u00d3"+ - "\u0001\u0000\u0000\u0000\u001a\u00db\u0001\u0000\u0000\u0000\u001c\u00de"+ - "\u0001\u0000\u0000\u0000\u001e\u00e6\u0001\u0000\u0000\u0000 \u00f2\u0001"+ - "\u0000\u0000\u0000\"\u00f6\u0001\u0000\u0000\u0000$\u00fd\u0001\u0000"+ - "\u0000\u0000&\u0101\u0001\u0000\u0000\u0000(\u0105\u0001\u0000\u0000\u0000"+ - "*\u0107\u0001\u0000\u0000\u0000,\u010b\u0001\u0000\u0000\u0000.\u010d"+ - "\u0001\u0000\u0000\u00000\u010f\u0001\u0000\u0000\u00002\u0112\u0001\u0000"+ - "\u0000\u00004\u0117\u0001\u0000\u0000\u00006\u011b\u0001\u0000\u0000\u0000"+ - "8\u011e\u0001\u0000\u0000\u0000:\u0122\u0001\u0000\u0000\u0000<\u012d"+ - "\u0001\u0000\u0000\u0000>\u012f\u0001\u0000\u0000\u0000@\u0134\u0001\u0000"+ - "\u0000\u0000B\u013d\u0001\u0000\u0000\u0000D\u0145\u0001\u0000\u0000\u0000"+ - "F\u0158\u0001\u0000\u0000\u0000H\u0161\u0001\u0000\u0000\u0000J\u016a"+ - "\u0001\u0000\u0000\u0000L\u0180\u0001\u0000\u0000\u0000N\u0188\u0001\u0000"+ - "\u0000\u0000P\u0198\u0001\u0000\u0000\u0000R\u01ac\u0001\u0000\u0000\u0000"+ - "T\u01ae\u0001\u0000\u0000\u0000V\u01b4\u0001\u0000\u0000\u0000X\u01bc"+ - "\u0001\u0000\u0000\u0000Z\u01c5\u0001\u0000\u0000\u0000\\^\u0003\u0002"+ - "\u0001\u0000]\\\u0001\u0000\u0000\u0000]^\u0001\u0000\u0000\u0000^b\u0001"+ - "\u0000\u0000\u0000_a\u0003\b\u0004\u0000`_\u0001\u0000\u0000\u0000ad\u0001"+ - "\u0000\u0000\u0000b`\u0001\u0000\u0000\u0000bc\u0001\u0000\u0000\u0000"+ - "ce\u0001\u0000\u0000\u0000db\u0001\u0000\u0000\u0000ef\u0005\u0000\u0000"+ - "\u0001f\u0001\u0001\u0000\u0000\u0000gh\u0005\u0003\u0000\u0000hn\u0003"+ - "\u0006\u0003\u0000ij\u0005\u0004\u0000\u0000jk\u0005+\u0000\u0000kl\u0003"+ - "\u0004\u0002\u0000lm\u0005,\u0000\u0000mo\u0001\u0000\u0000\u0000ni\u0001"+ - "\u0000\u0000\u0000no\u0001\u0000\u0000\u0000o\u0003\u0001\u0000\u0000"+ - "\u0000pr\u0003\u0006\u0003\u0000qp\u0001\u0000\u0000\u0000rs\u0001\u0000"+ - "\u0000\u0000sq\u0001\u0000\u0000\u0000st\u0001\u0000\u0000\u0000t\u0005"+ - "\u0001\u0000\u0000\u0000uz\u0005\u0019\u0000\u0000vw\u0005\'\u0000\u0000"+ - "wy\u0005\u0019\u0000\u0000xv\u0001\u0000\u0000\u0000y|\u0001\u0000\u0000"+ - "\u0000zx\u0001\u0000\u0000\u0000z{\u0001\u0000\u0000\u0000{\u0007\u0001"+ - "\u0000\u0000\u0000|z\u0001\u0000\u0000\u0000}\u007f\u0003\n\u0005\u0000"+ - "~}\u0001\u0000\u0000\u0000~\u007f\u0001\u0000\u0000\u0000\u007f\u0080"+ - "\u0001\u0000\u0000\u0000\u0080\u0083\u0005\u0019\u0000\u0000\u0081\u0082"+ - "\u0005\u0005\u0000\u0000\u0082\u0084\u0003\u0006\u0003\u0000\u0083\u0081"+ - "\u0001\u0000\u0000\u0000\u0083\u0084\u0001\u0000\u0000\u0000\u0084\u0085"+ - "\u0001\u0000\u0000\u0000\u0085\u0089\u0005+\u0000\u0000\u0086\u0088\u0003"+ - "\f\u0006\u0000\u0087\u0086\u0001\u0000\u0000\u0000\u0088\u008b\u0001\u0000"+ - "\u0000\u0000\u0089\u0087\u0001\u0000\u0000\u0000\u0089\u008a\u0001\u0000"+ - "\u0000\u0000\u008a\u008c\u0001\u0000\u0000\u0000\u008b\u0089\u0001\u0000"+ - "\u0000\u0000\u008c\u008d\u0005,\u0000\u0000\u008d\t\u0001\u0000\u0000"+ - "\u0000\u008e\u008f\u0007\u0000\u0000\u0000\u008f\u000b\u0001\u0000\u0000"+ - "\u0000\u0090\u0095\u0003\u000e\u0007\u0000\u0091\u0095\u0003\u0010\b\u0000"+ - "\u0092\u0095\u0003\u0012\t\u0000\u0093\u0095\u0003 \u0010\u0000\u0094"+ - "\u0090\u0001\u0000\u0000\u0000\u0094\u0091\u0001\u0000\u0000\u0000\u0094"+ - "\u0092\u0001\u0000\u0000\u0000\u0094\u0093\u0001\u0000\u0000\u0000\u0095"+ - "\r\u0001\u0000\u0000\u0000\u0096\u0097\u0003\u001c\u000e\u0000\u0097\u009a"+ - "\u0005\u0019\u0000\u0000\u0098\u0099\u0005\u001a\u0000\u0000\u0099\u009b"+ - "\u0003N\'\u0000\u009a\u0098\u0001\u0000\u0000\u0000\u009a\u009b\u0001"+ - "\u0000\u0000\u0000\u009b\u000f\u0001\u0000\u0000\u0000\u009c\u009d\u0005"+ - "\u0019\u0000\u0000\u009d\u009f\u0005)\u0000\u0000\u009e\u00a0\u0003\u0018"+ - "\f\u0000\u009f\u009e\u0001\u0000\u0000\u0000\u009f\u00a0\u0001\u0000\u0000"+ - "\u0000\u00a0\u00a1\u0001\u0000\u0000\u0000\u00a1\u00a2\u0005*\u0000\u0000"+ - "\u00a2\u00a6\u0005+\u0000\u0000\u00a3\u00a5\u0003 \u0010\u0000\u00a4\u00a3"+ - "\u0001\u0000\u0000\u0000\u00a5\u00a8\u0001\u0000\u0000\u0000\u00a6\u00a4"+ - "\u0001\u0000\u0000\u0000\u00a6\u00a7\u0001\u0000\u0000\u0000\u00a7\u00a9"+ - "\u0001\u0000\u0000\u0000\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a9\u00aa"+ - "\u0005,\u0000\u0000\u00aa\u0011\u0001\u0000\u0000\u0000\u00ab\u00ad\u0003"+ - "\u0016\u000b\u0000\u00ac\u00ae\u0003\n\u0005\u0000\u00ad\u00ac\u0001\u0000"+ - "\u0000\u0000\u00ad\u00ae\u0001\u0000\u0000\u0000\u00ae\u00b6\u0001\u0000"+ - "\u0000\u0000\u00af\u00b1\u0003\n\u0005\u0000\u00b0\u00af\u0001\u0000\u0000"+ - "\u0000\u00b0\u00b1\u0001\u0000\u0000\u0000\u00b1\u00b3\u0001\u0000\u0000"+ - "\u0000\u00b2\u00b4\u0003\u0016\u000b\u0000\u00b3\u00b2\u0001\u0000\u0000"+ - "\u0000\u00b3\u00b4\u0001\u0000\u0000\u0000\u00b4\u00b6\u0001\u0000\u0000"+ - "\u0000\u00b5\u00ab\u0001\u0000\u0000\u0000\u00b5\u00b0\u0001\u0000\u0000"+ - "\u0000\u00b6\u00b7\u0001\u0000\u0000\u0000\u00b7\u00b8\u0005\u0019\u0000"+ - "\u0000\u00b8\u00ba\u0005)\u0000\u0000\u00b9\u00bb\u0003\u0018\f\u0000"+ - "\u00ba\u00b9\u0001\u0000\u0000\u0000\u00ba\u00bb\u0001\u0000\u0000\u0000"+ - "\u00bb\u00bc\u0001\u0000\u0000\u0000\u00bc\u00bd\u0005*\u0000\u0000\u00bd"+ - "\u00c1\u0005+\u0000\u0000\u00be\u00c0\u0003 \u0010\u0000\u00bf\u00be\u0001"+ - "\u0000\u0000\u0000\u00c0\u00c3\u0001\u0000\u0000\u0000\u00c1\u00bf\u0001"+ - "\u0000\u0000\u0000\u00c1\u00c2\u0001\u0000\u0000\u0000\u00c2\u00c4\u0001"+ - "\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000\u0000\u00c4\u00c5\u0005"+ - ",\u0000\u0000\u00c5\u0013\u0001\u0000\u0000\u0000\u00c6\u00c9\u0005\u0019"+ - "\u0000\u0000\u00c7\u00c8\u0005(\u0000\u0000\u00c8\u00ca\u0005\u0019\u0000"+ - "\u0000\u00c9\u00c7\u0001\u0000\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000"+ - "\u0000\u00ca\u00cd\u0001\u0000\u0000\u0000\u00cb\u00cc\u0005(\u0000\u0000"+ - "\u00cc\u00ce\u0005\u0019\u0000\u0000\u00cd\u00cb\u0001\u0000\u0000\u0000"+ - "\u00cd\u00ce\u0001\u0000\u0000\u0000\u00ce\u0015\u0001\u0000\u0000\u0000"+ - "\u00cf\u00d0\u0005-\u0000\u0000\u00d0\u00d1\u0003\u0014\n\u0000\u00d1"+ - "\u00d2\u0005.\u0000\u0000\u00d2\u0017\u0001\u0000\u0000\u0000\u00d3\u00d8"+ - "\u0003\u001a\r\u0000\u00d4\u00d5\u0005(\u0000\u0000\u00d5\u00d7\u0003"+ - "\u001a\r\u0000\u00d6\u00d4\u0001\u0000\u0000\u0000\u00d7\u00da\u0001\u0000"+ - "\u0000\u0000\u00d8\u00d6\u0001\u0000\u0000\u0000\u00d8\u00d9\u0001\u0000"+ - "\u0000\u0000\u00d9\u0019\u0001\u0000\u0000\u0000\u00da\u00d8\u0001\u0000"+ - "\u0000\u0000\u00db\u00dc\u0003\u001c\u000e\u0000\u00dc\u00dd\u0005\u0019"+ - "\u0000\u0000\u00dd\u001b\u0001\u0000\u0000\u0000\u00de\u00e3\u0003\u001e"+ - "\u000f\u0000\u00df\u00e0\u0005-\u0000\u0000\u00e0\u00e2\u0005.\u0000\u0000"+ - "\u00e1\u00df\u0001\u0000\u0000\u0000\u00e2\u00e5\u0001\u0000\u0000\u0000"+ - "\u00e3\u00e1\u0001\u0000\u0000\u0000\u00e3\u00e4\u0001\u0000\u0000\u0000"+ - "\u00e4\u001d\u0001\u0000\u0000\u0000\u00e5\u00e3\u0001\u0000\u0000\u0000"+ - "\u00e6\u00e7\u0007\u0001\u0000\u0000\u00e7\u001f\u0001\u0000\u0000\u0000"+ - "\u00e8\u00f3\u0003\"\u0011\u0000\u00e9\u00f3\u0003$\u0012\u0000\u00ea"+ - "\u00f3\u0003*\u0015\u0000\u00eb\u00f3\u00034\u001a\u0000\u00ec\u00f3\u0003"+ - ">\u001f\u0000\u00ed\u00f3\u0003:\u001d\u0000\u00ee\u00f3\u0003D\"\u0000"+ - "\u00ef\u00f3\u0003J%\u0000\u00f0\u00f3\u0003&\u0013\u0000\u00f1\u00f3"+ - "\u0003.\u0017\u0000\u00f2\u00e8\u0001\u0000\u0000\u0000\u00f2\u00e9\u0001"+ - "\u0000\u0000\u0000\u00f2\u00ea\u0001\u0000\u0000\u0000\u00f2\u00eb\u0001"+ - "\u0000\u0000\u0000\u00f2\u00ec\u0001\u0000\u0000\u0000\u00f2\u00ed\u0001"+ - "\u0000\u0000\u0000\u00f2\u00ee\u0001\u0000\u0000\u0000\u00f2\u00ef\u0001"+ - "\u0000\u0000\u0000\u00f2\u00f0\u0001\u0000\u0000\u0000\u00f2\u00f1\u0001"+ - "\u0000\u0000\u0000\u00f3!\u0001\u0000\u0000\u0000\u00f4\u00f7\u0005\u0007"+ - "\u0000\u0000\u00f5\u00f7\u0003\u001c\u000e\u0000\u00f6\u00f4\u0001\u0000"+ - "\u0000\u0000\u00f6\u00f5\u0001\u0000\u0000\u0000\u00f7\u00f8\u0001\u0000"+ - "\u0000\u0000\u00f8\u00fb\u0005\u0019\u0000\u0000\u00f9\u00fa\u0005\u001a"+ - "\u0000\u0000\u00fa\u00fc\u0003N\'\u0000\u00fb\u00f9\u0001\u0000\u0000"+ - "\u0000\u00fb\u00fc\u0001\u0000\u0000\u0000\u00fc#\u0001\u0000\u0000\u0000"+ - "\u00fd\u00fe\u0003(\u0014\u0000\u00fe\u00ff\u0005\u001a\u0000\u0000\u00ff"+ - "\u0100\u0003N\'\u0000\u0100%\u0001\u0000\u0000\u0000\u0101\u0102\u0003"+ - "N\'\u0000\u0102\'\u0001\u0000\u0000\u0000\u0103\u0106\u0005\u0019\u0000"+ - "\u0000\u0104\u0106\u0003X,\u0000\u0105\u0103\u0001\u0000\u0000\u0000\u0105"+ - "\u0104\u0001\u0000\u0000\u0000\u0106)\u0001\u0000\u0000\u0000\u0107\u0108"+ - "\u0003,\u0016\u0000\u0108\u0109\u0005\u001a\u0000\u0000\u0109\u010a\u0003"+ - "0\u0018\u0000\u010a+\u0001\u0000\u0000\u0000\u010b\u010c\u0003\u0014\n"+ - "\u0000\u010c-\u0001\u0000\u0000\u0000\u010d\u010e\u00030\u0018\u0000\u010e"+ - "/\u0001\u0000\u0000\u0000\u010f\u0110\u00032\u0019\u0000\u0110\u0111\u0003"+ - "@ \u0000\u01111\u0001\u0000\u0000\u0000\u0112\u0113\u0005-\u0000\u0000"+ - "\u0113\u0114\u0003\u0014\n\u0000\u0114\u0115\u0005.\u0000\u0000\u0115"+ - "\u0116\u0005 \u0000\u0000\u01163\u0001\u0000\u0000\u0000\u0117\u0118\u0003"+ - "(\u0014\u0000\u0118\u0119\u0005\u001a\u0000\u0000\u0119\u011a\u00036\u001b"+ - "\u0000\u011a5\u0001\u0000\u0000\u0000\u011b\u011c\u00038\u001c\u0000\u011c"+ - "\u011d\u0005\t\u0000\u0000\u011d7\u0001\u0000\u0000\u0000\u011e\u011f"+ - "\u0005)\u0000\u0000\u011f\u0120\u0003\u001c\u000e\u0000\u0120\u0121\u0005"+ - "*\u0000\u0000\u01219\u0001\u0000\u0000\u0000\u0122\u0123\u0005\b\u0000"+ - "\u0000\u0123\u0124\u0003<\u001e\u0000\u0124;\u0001\u0000\u0000\u0000\u0125"+ - "\u0127\u00032\u0019\u0000\u0126\u0125\u0001\u0000\u0000\u0000\u0126\u0127"+ - "\u0001\u0000\u0000\u0000\u0127\u0128\u0001\u0000\u0000\u0000\u0128\u012e"+ - "\u0003@ \u0000\u0129\u012a\u0005\u0019\u0000\u0000\u012a\u012b\u0005\u001a"+ - "\u0000\u0000\u012b\u012e\u0003N\'\u0000\u012c\u012e\u0003N\'\u0000\u012d"+ - "\u0126\u0001\u0000\u0000\u0000\u012d\u0129\u0001\u0000\u0000\u0000\u012d"+ - "\u012c\u0001\u0000\u0000\u0000\u012e=\u0001\u0000\u0000\u0000\u012f\u0130"+ - "\u0003@ \u0000\u0130?\u0001\u0000\u0000\u0000\u0131\u0132\u0003\u0006"+ - "\u0003\u0000\u0132\u0133\u0005\'\u0000\u0000\u0133\u0135\u0001\u0000\u0000"+ - "\u0000\u0134\u0131\u0001\u0000\u0000\u0000\u0134\u0135\u0001\u0000\u0000"+ - "\u0000\u0135\u0136\u0001\u0000\u0000\u0000\u0136\u0137\u0005\u0019\u0000"+ - "\u0000\u0137\u0139\u0005)\u0000\u0000\u0138\u013a\u0003B!\u0000\u0139"+ - "\u0138\u0001\u0000\u0000\u0000\u0139\u013a\u0001\u0000\u0000\u0000\u013a"+ - "\u013b\u0001\u0000\u0000\u0000\u013b\u013c\u0005*\u0000\u0000\u013cA\u0001"+ - "\u0000\u0000\u0000\u013d\u0142\u0003N\'\u0000\u013e\u013f\u0005(\u0000"+ - "\u0000\u013f\u0141\u0003N\'\u0000\u0140\u013e\u0001\u0000\u0000\u0000"+ - "\u0141\u0144\u0001\u0000\u0000\u0000\u0142\u0140\u0001\u0000\u0000\u0000"+ - "\u0142\u0143\u0001\u0000\u0000\u0000\u0143C\u0001\u0000\u0000\u0000\u0144"+ - "\u0142\u0001\u0000\u0000\u0000\u0145\u0146\u0005\n\u0000\u0000\u0146\u0147"+ - "\u0003N\'\u0000\u0147\u014e\u0003F#\u0000\u0148\u0149\u0005\f\u0000\u0000"+ - "\u0149\u014a\u0003N\'\u0000\u014a\u014b\u0003F#\u0000\u014b\u014d\u0001"+ - "\u0000\u0000\u0000\u014c\u0148\u0001\u0000\u0000\u0000\u014d\u0150\u0001"+ - "\u0000\u0000\u0000\u014e\u014c\u0001\u0000\u0000\u0000\u014e\u014f\u0001"+ - "\u0000\u0000\u0000\u014f\u0156\u0001\u0000\u0000\u0000\u0150\u014e\u0001"+ - "\u0000\u0000\u0000\u0151\u0154\u0005\u000b\u0000\u0000\u0152\u0155\u0003"+ - "D\"\u0000\u0153\u0155\u0003H$\u0000\u0154\u0152\u0001\u0000\u0000\u0000"+ - "\u0154\u0153\u0001\u0000\u0000\u0000\u0155\u0157\u0001\u0000\u0000\u0000"+ - "\u0156\u0151\u0001\u0000\u0000\u0000\u0156\u0157\u0001\u0000\u0000\u0000"+ - "\u0157E\u0001\u0000\u0000\u0000\u0158\u015c\u0005+\u0000\u0000\u0159\u015b"+ - "\u0003 \u0010\u0000\u015a\u0159\u0001\u0000\u0000\u0000\u015b\u015e\u0001"+ - "\u0000\u0000\u0000\u015c\u015a\u0001\u0000\u0000\u0000\u015c\u015d\u0001"+ - "\u0000\u0000\u0000\u015d\u015f\u0001\u0000\u0000\u0000\u015e\u015c\u0001"+ - "\u0000\u0000\u0000\u015f\u0160\u0005,\u0000\u0000\u0160G\u0001\u0000\u0000"+ - "\u0000\u0161\u0165\u0005+\u0000\u0000\u0162\u0164\u0003 \u0010\u0000\u0163"+ - "\u0162\u0001\u0000\u0000\u0000\u0164\u0167\u0001\u0000\u0000\u0000\u0165"+ - "\u0163\u0001\u0000\u0000\u0000\u0165\u0166\u0001\u0000\u0000\u0000\u0166"+ - "\u0168\u0001\u0000\u0000\u0000\u0167\u0165\u0001\u0000\u0000\u0000\u0168"+ - "\u0169\u0005,\u0000\u0000\u0169I\u0001\u0000\u0000\u0000\u016a\u016b\u0005"+ - "\r\u0000\u0000\u016b\u016e\u0005\u0019\u0000\u0000\u016c\u016d\u0005\u000e"+ - "\u0000\u0000\u016d\u016f\u0003L&\u0000\u016e\u016c\u0001\u0000\u0000\u0000"+ - "\u016e\u016f\u0001\u0000\u0000\u0000\u016f\u0170\u0001\u0000\u0000\u0000"+ - "\u0170\u0171\u0005\u000f\u0000\u0000\u0171\u0172\u0003N\'\u0000\u0172"+ - "\u0173\u0005\u0010\u0000\u0000\u0173\u0174\u0003N\'\u0000\u0174\u0178"+ - "\u0005+\u0000\u0000\u0175\u0177\u0003 \u0010\u0000\u0176\u0175\u0001\u0000"+ - "\u0000\u0000\u0177\u017a\u0001\u0000\u0000\u0000\u0178\u0176\u0001\u0000"+ - "\u0000\u0000\u0178\u0179\u0001\u0000\u0000\u0000\u0179\u017b\u0001\u0000"+ - "\u0000\u0000\u017a\u0178\u0001\u0000\u0000\u0000\u017b\u017c\u0005,\u0000"+ - "\u0000\u017cK\u0001\u0000\u0000\u0000\u017d\u017e\u0007\u0002\u0000\u0000"+ - "\u017e\u0181\u0003N\'\u0000\u017f\u0181\u0003N\'\u0000\u0180\u017d\u0001"+ - "\u0000\u0000\u0000\u0180\u017f\u0001\u0000\u0000\u0000\u0181M\u0001\u0000"+ - "\u0000\u0000\u0182\u0183\u0006\'\uffff\uffff\u0000\u0183\u0184\u0007\u0003"+ - "\u0000\u0000\u0184\u0189\u0003N\'\u0007\u0185\u0189\u0003P(\u0000\u0186"+ - "\u0189\u0003@ \u0000\u0187\u0189\u0003Z-\u0000\u0188\u0182\u0001\u0000"+ - "\u0000\u0000\u0188\u0185\u0001\u0000\u0000\u0000\u0188\u0186\u0001\u0000"+ - "\u0000\u0000\u0188\u0187\u0001\u0000\u0000\u0000\u0189\u0195\u0001\u0000"+ - "\u0000\u0000\u018a\u018b\n\u0006\u0000\u0000\u018b\u018c\u0007\u0004\u0000"+ - "\u0000\u018c\u0194\u0003N\'\u0007\u018d\u018e\n\u0005\u0000\u0000\u018e"+ - "\u018f\u0007\u0003\u0000\u0000\u018f\u0194\u0003N\'\u0006\u0190\u0191"+ - "\n\u0004\u0000\u0000\u0191\u0192\u0007\u0005\u0000\u0000\u0192\u0194\u0003"+ - "N\'\u0005\u0193\u018a\u0001\u0000\u0000\u0000\u0193\u018d\u0001\u0000"+ - "\u0000\u0000\u0193\u0190\u0001\u0000\u0000\u0000\u0194\u0197\u0001\u0000"+ - "\u0000\u0000\u0195\u0193\u0001\u0000\u0000\u0000\u0195\u0196\u0001\u0000"+ - "\u0000\u0000\u0196O\u0001\u0000\u0000\u0000\u0197\u0195\u0001\u0000\u0000"+ - "\u0000\u0198\u019f\u0003R)\u0000\u0199\u019a\u0005-\u0000\u0000\u019a"+ - "\u019b\u0003N\'\u0000\u019b\u019c\u0005.\u0000\u0000\u019c\u019e\u0001"+ - "\u0000\u0000\u0000\u019d\u0199\u0001\u0000\u0000\u0000\u019e\u01a1\u0001"+ - "\u0000\u0000\u0000\u019f\u019d\u0001\u0000\u0000\u0000\u019f\u01a0\u0001"+ - "\u0000\u0000\u0000\u01a0Q\u0001\u0000\u0000\u0000\u01a1\u019f\u0001\u0000"+ - "\u0000\u0000\u01a2\u01ad\u0005\u0019\u0000\u0000\u01a3\u01ad\u0005\u0015"+ - "\u0000\u0000\u01a4\u01ad\u0005\u0016\u0000\u0000\u01a5\u01ad\u0005\u0017"+ - "\u0000\u0000\u01a6\u01ad\u0005\u0018\u0000\u0000\u01a7\u01a8\u0005)\u0000"+ - "\u0000\u01a8\u01a9\u0003N\'\u0000\u01a9\u01aa\u0005*\u0000\u0000\u01aa"+ - "\u01ad\u0001\u0000\u0000\u0000\u01ab\u01ad\u0003T*\u0000\u01ac\u01a2\u0001"+ - "\u0000\u0000\u0000\u01ac\u01a3\u0001\u0000\u0000\u0000\u01ac\u01a4\u0001"+ - "\u0000\u0000\u0000\u01ac\u01a5\u0001\u0000\u0000\u0000\u01ac\u01a6\u0001"+ - "\u0000\u0000\u0000\u01ac\u01a7\u0001\u0000\u0000\u0000\u01ac\u01ab\u0001"+ - "\u0000\u0000\u0000\u01adS\u0001\u0000\u0000\u0000\u01ae\u01b0\u0005-\u0000"+ - "\u0000\u01af\u01b1\u0003V+\u0000\u01b0\u01af\u0001\u0000\u0000\u0000\u01b0"+ - "\u01b1\u0001\u0000\u0000\u0000\u01b1\u01b2\u0001\u0000\u0000\u0000\u01b2"+ - "\u01b3\u0005.\u0000\u0000\u01b3U\u0001\u0000\u0000\u0000\u01b4\u01b9\u0003"+ - "N\'\u0000\u01b5\u01b6\u0005(\u0000\u0000\u01b6\u01b8\u0003N\'\u0000\u01b7"+ - "\u01b5\u0001\u0000\u0000\u0000\u01b8\u01bb\u0001\u0000\u0000\u0000\u01b9"+ - "\u01b7\u0001\u0000\u0000\u0000\u01b9\u01ba\u0001\u0000\u0000\u0000\u01ba"+ - "W\u0001\u0000\u0000\u0000\u01bb\u01b9\u0001\u0000\u0000\u0000\u01bc\u01c1"+ - "\u0005\u0019\u0000\u0000\u01bd\u01be\u0005-\u0000\u0000\u01be\u01bf\u0003"+ - "N\'\u0000\u01bf\u01c0\u0005.\u0000\u0000\u01c0\u01c2\u0001\u0000\u0000"+ - "\u0000\u01c1\u01bd\u0001\u0000\u0000\u0000\u01c2\u01c3\u0001\u0000\u0000"+ - "\u0000\u01c3\u01c1\u0001\u0000\u0000\u0000\u01c3\u01c4\u0001\u0000\u0000"+ - "\u0000\u01c4Y\u0001\u0000\u0000\u0000\u01c5\u01c6\u0005)\u0000\u0000\u01c6"+ - "\u01c7\u0003\u001c\u000e\u0000\u01c7\u01c8\u0005*\u0000\u0000\u01c8\u01c9"+ - "\u0003N\'\u0000\u01c9[\u0001\u0000\u0000\u0000/]bnsz~\u0083\u0089\u0094"+ - "\u009a\u009f\u00a6\u00ad\u00b0\u00b3\u00b5\u00ba\u00c1\u00c9\u00cd\u00d8"+ - "\u00e3\u00f2\u00f6\u00fb\u0105\u0126\u012d\u0134\u0139\u0142\u014e\u0154"+ - "\u0156\u015c\u0165\u016e\u0178\u0180\u0188\u0193\u0195\u019f\u01ac\u01b0"+ - "\u01b9\u01c3"; - public static final ATN _ATN = - new ATNDeserializer().deserialize(_serializedATN.toCharArray()); - static { - _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; - for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { - _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); - } - } -} \ No newline at end of file From 2e5f42f87bc8fc836376f5303794d77ae262261c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:59:43 +0800 Subject: [PATCH 22/54] Delete src/main/java/cod/ast/CoderiveLexer.java --- src/main/java/cod/ast/CoderiveLexer.java | 334 ----------------------- 1 file changed, 334 deletions(-) delete mode 100644 src/main/java/cod/ast/CoderiveLexer.java diff --git a/src/main/java/cod/ast/CoderiveLexer.java b/src/main/java/cod/ast/CoderiveLexer.java deleted file mode 100644 index b729dcd5..00000000 --- a/src/main/java/cod/ast/CoderiveLexer.java +++ /dev/null @@ -1,334 +0,0 @@ -// Generated from CoderiveLexer.g4 by ANTLR 4.13.2 - -package cod.ast; - -import org.antlr.v4.runtime.Lexer; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.TokenStream; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.*; -import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.misc.*; - -@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) -public class CoderiveLexer extends Lexer { - static { RuntimeMetaData.checkVersion("4.13.2", RuntimeMetaData.VERSION); } - - protected static final DFA[] _decisionToDFA; - protected static final PredictionContextCache _sharedContextCache = - new PredictionContextCache(); - public static final int - SHIP=1, LOCAL=2, UNIT=3, GET=4, EXTEND=5, THIS=6, VAR=7, OUTPUT=8, INPUT=9, - IF=10, ELSE=11, ELIF=12, FOR=13, BY=14, IN=15, TO=16, INT=17, STRING=18, - FLOAT=19, BOOL=20, INT_LIT=21, FLOAT_LIT=22, STRING_LIT=23, BOOL_LIT=24, - ID=25, ASSIGN=26, PLUS=27, MINUS=28, MUL=29, DIV=30, MOD=31, COLON=32, - GT=33, LT=34, GTE=35, LTE=36, EQ=37, NEQ=38, DOT=39, COMMA=40, LPAREN=41, - RPAREN=42, LBRACE=43, RBRACE=44, LBRACKET=45, RBRACKET=46, LINE_COMMENT=47, - BLOCK_COMMENT=48, WS=49; - public static String[] channelNames = { - "DEFAULT_TOKEN_CHANNEL", "HIDDEN" - }; - - public static String[] modeNames = { - "DEFAULT_MODE" - }; - - private static String[] makeRuleNames() { - return new String[] { - "SHIP", "LOCAL", "UNIT", "GET", "EXTEND", "THIS", "VAR", "OUTPUT", "INPUT", - "IF", "ELSE", "ELIF", "FOR", "BY", "IN", "TO", "INT", "STRING", "FLOAT", - "BOOL", "INT_LIT", "FLOAT_LIT", "STRING_LIT", "BOOL_LIT", "ID", "ASSIGN", - "PLUS", "MINUS", "MUL", "DIV", "MOD", "COLON", "GT", "LT", "GTE", "LTE", - "EQ", "NEQ", "DOT", "COMMA", "LPAREN", "RPAREN", "LBRACE", "RBRACE", - "LBRACKET", "RBRACKET", "LINE_COMMENT", "BLOCK_COMMENT", "WS" - }; - } - public static final String[] ruleNames = makeRuleNames(); - - private static String[] makeLiteralNames() { - return new String[] { - null, "'ship'", "'local'", "'unit'", "'get'", "'extend'", "'this'", "'var'", - "'output'", "'input'", "'if'", "'else'", "'elif'", "'for'", "'by'", "'in'", - "'to'", "'int'", "'string'", "'float'", "'bool'", null, null, null, null, - null, "'='", "'+'", "'-'", "'*'", "'/'", "'%'", "':'", "'>'", "'<'", - "'>='", "'<='", "'=='", "'!='", "'.'", "','", "'('", "')'", "'{'", "'}'", - "'['", "']'" - }; - } - private static final String[] _LITERAL_NAMES = makeLiteralNames(); - private static String[] makeSymbolicNames() { - return new String[] { - null, "SHIP", "LOCAL", "UNIT", "GET", "EXTEND", "THIS", "VAR", "OUTPUT", - "INPUT", "IF", "ELSE", "ELIF", "FOR", "BY", "IN", "TO", "INT", "STRING", - "FLOAT", "BOOL", "INT_LIT", "FLOAT_LIT", "STRING_LIT", "BOOL_LIT", "ID", - "ASSIGN", "PLUS", "MINUS", "MUL", "DIV", "MOD", "COLON", "GT", "LT", - "GTE", "LTE", "EQ", "NEQ", "DOT", "COMMA", "LPAREN", "RPAREN", "LBRACE", - "RBRACE", "LBRACKET", "RBRACKET", "LINE_COMMENT", "BLOCK_COMMENT", "WS" - }; - } - private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); - public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); - - /** - * @deprecated Use {@link #VOCABULARY} instead. - */ - @Deprecated - public static final String[] tokenNames; - static { - tokenNames = new String[_SYMBOLIC_NAMES.length]; - for (int i = 0; i < tokenNames.length; i++) { - tokenNames[i] = VOCABULARY.getLiteralName(i); - if (tokenNames[i] == null) { - tokenNames[i] = VOCABULARY.getSymbolicName(i); - } - - if (tokenNames[i] == null) { - tokenNames[i] = ""; - } - } - } - - @Override - @Deprecated - public String[] getTokenNames() { - return tokenNames; - } - - @Override - - public Vocabulary getVocabulary() { - return VOCABULARY; - } - - - public CoderiveLexer(CharStream input) { - super(input); - _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); - } - - @Override - public String getGrammarFileName() { return "CoderiveLexer.g4"; } - - @Override - public String[] getRuleNames() { return ruleNames; } - - @Override - public String getSerializedATN() { return _serializedATN; } - - @Override - public String[] getChannelNames() { return channelNames; } - - @Override - public String[] getModeNames() { return modeNames; } - - @Override - public ATN getATN() { return _ATN; } - - public static final String _serializedATN = - "\u0004\u00001\u013f\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+ - "\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+ - "\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+ - "\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+ - "\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002"+ - "\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002"+ - "\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002"+ - "\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002"+ - "\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002"+ - "\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002"+ - "\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007"+ - "!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007"+ - "&\u0002\'\u0007\'\u0002(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007"+ - "+\u0002,\u0007,\u0002-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u0007"+ - "0\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002"+ - "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003"+ - "\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+ - "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+ - "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ - "\u0001\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\t\u0001"+ - "\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\u000b\u0001\u000b"+ - "\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+ - "\r\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001"+ - "\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ - "\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+ - "\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+ - "\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ - "\u0014\u0004\u0014\u00c6\b\u0014\u000b\u0014\f\u0014\u00c7\u0001\u0015"+ - "\u0004\u0015\u00cb\b\u0015\u000b\u0015\f\u0015\u00cc\u0001\u0015\u0001"+ - "\u0015\u0004\u0015\u00d1\b\u0015\u000b\u0015\f\u0015\u00d2\u0001\u0016"+ - "\u0001\u0016\u0001\u0016\u0001\u0016\u0005\u0016\u00d9\b\u0016\n\u0016"+ - "\f\u0016\u00dc\t\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ - "\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017"+ - "\u0001\u0017\u0003\u0017\u00e9\b\u0017\u0001\u0018\u0001\u0018\u0005\u0018"+ - "\u00ed\b\u0018\n\u0018\f\u0018\u00f0\t\u0018\u0001\u0019\u0001\u0019\u0001"+ - "\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001"+ - "\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f\u0001"+ - " \u0001 \u0001!\u0001!\u0001\"\u0001\"\u0001\"\u0001#\u0001#\u0001#\u0001"+ - "$\u0001$\u0001$\u0001%\u0001%\u0001%\u0001&\u0001&\u0001\'\u0001\'\u0001"+ - "(\u0001(\u0001)\u0001)\u0001*\u0001*\u0001+\u0001+\u0001,\u0001,\u0001"+ - "-\u0001-\u0001.\u0001.\u0001.\u0001.\u0005.\u0124\b.\n.\f.\u0127\t.\u0001"+ - ".\u0001.\u0001/\u0001/\u0001/\u0001/\u0005/\u012f\b/\n/\f/\u0132\t/\u0001"+ - "/\u0001/\u0001/\u0001/\u0001/\u00010\u00040\u013a\b0\u000b0\f0\u013b\u0001"+ - "0\u00010\u0001\u0130\u00001\u0001\u0001\u0003\u0002\u0005\u0003\u0007"+ - "\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013\n\u0015\u000b"+ - "\u0017\f\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010!\u0011#\u0012%\u0013"+ - "\'\u0014)\u0015+\u0016-\u0017/\u00181\u00193\u001a5\u001b7\u001c9\u001d"+ - ";\u001e=\u001f? A!C\"E#G$I%K&M\'O(Q)S*U+W,Y-[.]/_0a1\u0001\u0000\u0006"+ - "\u0001\u000009\u0002\u0000\"\"\\\\\u0003\u0000AZ__az\u0004\u000009AZ_"+ - "_az\u0002\u0000\n\n\r\r\u0003\u0000\t\n\r\r \u0148\u0000\u0001\u0001"+ - "\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000\u0005\u0001"+ - "\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000\t\u0001\u0000"+ - "\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r\u0001\u0000\u0000"+ - "\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011\u0001\u0000\u0000"+ - "\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000"+ - "\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019\u0001\u0000\u0000"+ - "\u0000\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d\u0001\u0000\u0000"+ - "\u0000\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001\u0000\u0000\u0000"+ - "\u0000#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000\u0000\u0000\'"+ - "\u0001\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001\u0000"+ - "\u0000\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000\u0000"+ - "\u00001\u0001\u0000\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u00005"+ - "\u0001\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000"+ - "\u0000\u0000\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000"+ - "\u0000?\u0001\u0000\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000C"+ - "\u0001\u0000\u0000\u0000\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001\u0000"+ - "\u0000\u0000\u0000I\u0001\u0000\u0000\u0000\u0000K\u0001\u0000\u0000\u0000"+ - "\u0000M\u0001\u0000\u0000\u0000\u0000O\u0001\u0000\u0000\u0000\u0000Q"+ - "\u0001\u0000\u0000\u0000\u0000S\u0001\u0000\u0000\u0000\u0000U\u0001\u0000"+ - "\u0000\u0000\u0000W\u0001\u0000\u0000\u0000\u0000Y\u0001\u0000\u0000\u0000"+ - "\u0000[\u0001\u0000\u0000\u0000\u0000]\u0001\u0000\u0000\u0000\u0000_"+ - "\u0001\u0000\u0000\u0000\u0000a\u0001\u0000\u0000\u0000\u0001c\u0001\u0000"+ - "\u0000\u0000\u0003h\u0001\u0000\u0000\u0000\u0005n\u0001\u0000\u0000\u0000"+ - "\u0007s\u0001\u0000\u0000\u0000\tw\u0001\u0000\u0000\u0000\u000b~\u0001"+ - "\u0000\u0000\u0000\r\u0083\u0001\u0000\u0000\u0000\u000f\u0087\u0001\u0000"+ - "\u0000\u0000\u0011\u008e\u0001\u0000\u0000\u0000\u0013\u0094\u0001\u0000"+ - "\u0000\u0000\u0015\u0097\u0001\u0000\u0000\u0000\u0017\u009c\u0001\u0000"+ - "\u0000\u0000\u0019\u00a1\u0001\u0000\u0000\u0000\u001b\u00a5\u0001\u0000"+ - "\u0000\u0000\u001d\u00a8\u0001\u0000\u0000\u0000\u001f\u00ab\u0001\u0000"+ - "\u0000\u0000!\u00ae\u0001\u0000\u0000\u0000#\u00b2\u0001\u0000\u0000\u0000"+ - "%\u00b9\u0001\u0000\u0000\u0000\'\u00bf\u0001\u0000\u0000\u0000)\u00c5"+ - "\u0001\u0000\u0000\u0000+\u00ca\u0001\u0000\u0000\u0000-\u00d4\u0001\u0000"+ - "\u0000\u0000/\u00e8\u0001\u0000\u0000\u00001\u00ea\u0001\u0000\u0000\u0000"+ - "3\u00f1\u0001\u0000\u0000\u00005\u00f3\u0001\u0000\u0000\u00007\u00f5"+ - "\u0001\u0000\u0000\u00009\u00f7\u0001\u0000\u0000\u0000;\u00f9\u0001\u0000"+ - "\u0000\u0000=\u00fb\u0001\u0000\u0000\u0000?\u00fd\u0001\u0000\u0000\u0000"+ - "A\u00ff\u0001\u0000\u0000\u0000C\u0101\u0001\u0000\u0000\u0000E\u0103"+ - "\u0001\u0000\u0000\u0000G\u0106\u0001\u0000\u0000\u0000I\u0109\u0001\u0000"+ - "\u0000\u0000K\u010c\u0001\u0000\u0000\u0000M\u010f\u0001\u0000\u0000\u0000"+ - "O\u0111\u0001\u0000\u0000\u0000Q\u0113\u0001\u0000\u0000\u0000S\u0115"+ - "\u0001\u0000\u0000\u0000U\u0117\u0001\u0000\u0000\u0000W\u0119\u0001\u0000"+ - "\u0000\u0000Y\u011b\u0001\u0000\u0000\u0000[\u011d\u0001\u0000\u0000\u0000"+ - "]\u011f\u0001\u0000\u0000\u0000_\u012a\u0001\u0000\u0000\u0000a\u0139"+ - "\u0001\u0000\u0000\u0000cd\u0005s\u0000\u0000de\u0005h\u0000\u0000ef\u0005"+ - "i\u0000\u0000fg\u0005p\u0000\u0000g\u0002\u0001\u0000\u0000\u0000hi\u0005"+ - "l\u0000\u0000ij\u0005o\u0000\u0000jk\u0005c\u0000\u0000kl\u0005a\u0000"+ - "\u0000lm\u0005l\u0000\u0000m\u0004\u0001\u0000\u0000\u0000no\u0005u\u0000"+ - "\u0000op\u0005n\u0000\u0000pq\u0005i\u0000\u0000qr\u0005t\u0000\u0000"+ - "r\u0006\u0001\u0000\u0000\u0000st\u0005g\u0000\u0000tu\u0005e\u0000\u0000"+ - "uv\u0005t\u0000\u0000v\b\u0001\u0000\u0000\u0000wx\u0005e\u0000\u0000"+ - "xy\u0005x\u0000\u0000yz\u0005t\u0000\u0000z{\u0005e\u0000\u0000{|\u0005"+ - "n\u0000\u0000|}\u0005d\u0000\u0000}\n\u0001\u0000\u0000\u0000~\u007f\u0005"+ - "t\u0000\u0000\u007f\u0080\u0005h\u0000\u0000\u0080\u0081\u0005i\u0000"+ - "\u0000\u0081\u0082\u0005s\u0000\u0000\u0082\f\u0001\u0000\u0000\u0000"+ - "\u0083\u0084\u0005v\u0000\u0000\u0084\u0085\u0005a\u0000\u0000\u0085\u0086"+ - "\u0005r\u0000\u0000\u0086\u000e\u0001\u0000\u0000\u0000\u0087\u0088\u0005"+ - "o\u0000\u0000\u0088\u0089\u0005u\u0000\u0000\u0089\u008a\u0005t\u0000"+ - "\u0000\u008a\u008b\u0005p\u0000\u0000\u008b\u008c\u0005u\u0000\u0000\u008c"+ - "\u008d\u0005t\u0000\u0000\u008d\u0010\u0001\u0000\u0000\u0000\u008e\u008f"+ - "\u0005i\u0000\u0000\u008f\u0090\u0005n\u0000\u0000\u0090\u0091\u0005p"+ - "\u0000\u0000\u0091\u0092\u0005u\u0000\u0000\u0092\u0093\u0005t\u0000\u0000"+ - "\u0093\u0012\u0001\u0000\u0000\u0000\u0094\u0095\u0005i\u0000\u0000\u0095"+ - "\u0096\u0005f\u0000\u0000\u0096\u0014\u0001\u0000\u0000\u0000\u0097\u0098"+ - "\u0005e\u0000\u0000\u0098\u0099\u0005l\u0000\u0000\u0099\u009a\u0005s"+ - "\u0000\u0000\u009a\u009b\u0005e\u0000\u0000\u009b\u0016\u0001\u0000\u0000"+ - "\u0000\u009c\u009d\u0005e\u0000\u0000\u009d\u009e\u0005l\u0000\u0000\u009e"+ - "\u009f\u0005i\u0000\u0000\u009f\u00a0\u0005f\u0000\u0000\u00a0\u0018\u0001"+ - "\u0000\u0000\u0000\u00a1\u00a2\u0005f\u0000\u0000\u00a2\u00a3\u0005o\u0000"+ - "\u0000\u00a3\u00a4\u0005r\u0000\u0000\u00a4\u001a\u0001\u0000\u0000\u0000"+ - "\u00a5\u00a6\u0005b\u0000\u0000\u00a6\u00a7\u0005y\u0000\u0000\u00a7\u001c"+ - "\u0001\u0000\u0000\u0000\u00a8\u00a9\u0005i\u0000\u0000\u00a9\u00aa\u0005"+ - "n\u0000\u0000\u00aa\u001e\u0001\u0000\u0000\u0000\u00ab\u00ac\u0005t\u0000"+ - "\u0000\u00ac\u00ad\u0005o\u0000\u0000\u00ad \u0001\u0000\u0000\u0000\u00ae"+ - "\u00af\u0005i\u0000\u0000\u00af\u00b0\u0005n\u0000\u0000\u00b0\u00b1\u0005"+ - "t\u0000\u0000\u00b1\"\u0001\u0000\u0000\u0000\u00b2\u00b3\u0005s\u0000"+ - "\u0000\u00b3\u00b4\u0005t\u0000\u0000\u00b4\u00b5\u0005r\u0000\u0000\u00b5"+ - "\u00b6\u0005i\u0000\u0000\u00b6\u00b7\u0005n\u0000\u0000\u00b7\u00b8\u0005"+ - "g\u0000\u0000\u00b8$\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005f\u0000"+ - "\u0000\u00ba\u00bb\u0005l\u0000\u0000\u00bb\u00bc\u0005o\u0000\u0000\u00bc"+ - "\u00bd\u0005a\u0000\u0000\u00bd\u00be\u0005t\u0000\u0000\u00be&\u0001"+ - "\u0000\u0000\u0000\u00bf\u00c0\u0005b\u0000\u0000\u00c0\u00c1\u0005o\u0000"+ - "\u0000\u00c1\u00c2\u0005o\u0000\u0000\u00c2\u00c3\u0005l\u0000\u0000\u00c3"+ - "(\u0001\u0000\u0000\u0000\u00c4\u00c6\u0007\u0000\u0000\u0000\u00c5\u00c4"+ - "\u0001\u0000\u0000\u0000\u00c6\u00c7\u0001\u0000\u0000\u0000\u00c7\u00c5"+ - "\u0001\u0000\u0000\u0000\u00c7\u00c8\u0001\u0000\u0000\u0000\u00c8*\u0001"+ - "\u0000\u0000\u0000\u00c9\u00cb\u0007\u0000\u0000\u0000\u00ca\u00c9\u0001"+ - "\u0000\u0000\u0000\u00cb\u00cc\u0001\u0000\u0000\u0000\u00cc\u00ca\u0001"+ - "\u0000\u0000\u0000\u00cc\u00cd\u0001\u0000\u0000\u0000\u00cd\u00ce\u0001"+ - "\u0000\u0000\u0000\u00ce\u00d0\u0005.\u0000\u0000\u00cf\u00d1\u0007\u0000"+ - "\u0000\u0000\u00d0\u00cf\u0001\u0000\u0000\u0000\u00d1\u00d2\u0001\u0000"+ - "\u0000\u0000\u00d2\u00d0\u0001\u0000\u0000\u0000\u00d2\u00d3\u0001\u0000"+ - "\u0000\u0000\u00d3,\u0001\u0000\u0000\u0000\u00d4\u00da\u0005\"\u0000"+ - "\u0000\u00d5\u00d9\b\u0001\u0000\u0000\u00d6\u00d7\u0005\\\u0000\u0000"+ - "\u00d7\u00d9\t\u0000\u0000\u0000\u00d8\u00d5\u0001\u0000\u0000\u0000\u00d8"+ - "\u00d6\u0001\u0000\u0000\u0000\u00d9\u00dc\u0001\u0000\u0000\u0000\u00da"+ - "\u00d8\u0001\u0000\u0000\u0000\u00da\u00db\u0001\u0000\u0000\u0000\u00db"+ - "\u00dd\u0001\u0000\u0000\u0000\u00dc\u00da\u0001\u0000\u0000\u0000\u00dd"+ - "\u00de\u0005\"\u0000\u0000\u00de.\u0001\u0000\u0000\u0000\u00df\u00e0"+ - "\u0005t\u0000\u0000\u00e0\u00e1\u0005r\u0000\u0000\u00e1\u00e2\u0005u"+ - "\u0000\u0000\u00e2\u00e9\u0005e\u0000\u0000\u00e3\u00e4\u0005f\u0000\u0000"+ - "\u00e4\u00e5\u0005a\u0000\u0000\u00e5\u00e6\u0005l\u0000\u0000\u00e6\u00e7"+ - "\u0005s\u0000\u0000\u00e7\u00e9\u0005e\u0000\u0000\u00e8\u00df\u0001\u0000"+ - "\u0000\u0000\u00e8\u00e3\u0001\u0000\u0000\u0000\u00e90\u0001\u0000\u0000"+ - "\u0000\u00ea\u00ee\u0007\u0002\u0000\u0000\u00eb\u00ed\u0007\u0003\u0000"+ - "\u0000\u00ec\u00eb\u0001\u0000\u0000\u0000\u00ed\u00f0\u0001\u0000\u0000"+ - "\u0000\u00ee\u00ec\u0001\u0000\u0000\u0000\u00ee\u00ef\u0001\u0000\u0000"+ - "\u0000\u00ef2\u0001\u0000\u0000\u0000\u00f0\u00ee\u0001\u0000\u0000\u0000"+ - "\u00f1\u00f2\u0005=\u0000\u0000\u00f24\u0001\u0000\u0000\u0000\u00f3\u00f4"+ - "\u0005+\u0000\u0000\u00f46\u0001\u0000\u0000\u0000\u00f5\u00f6\u0005-"+ - "\u0000\u0000\u00f68\u0001\u0000\u0000\u0000\u00f7\u00f8\u0005*\u0000\u0000"+ - "\u00f8:\u0001\u0000\u0000\u0000\u00f9\u00fa\u0005/\u0000\u0000\u00fa<"+ - "\u0001\u0000\u0000\u0000\u00fb\u00fc\u0005%\u0000\u0000\u00fc>\u0001\u0000"+ - "\u0000\u0000\u00fd\u00fe\u0005:\u0000\u0000\u00fe@\u0001\u0000\u0000\u0000"+ - "\u00ff\u0100\u0005>\u0000\u0000\u0100B\u0001\u0000\u0000\u0000\u0101\u0102"+ - "\u0005<\u0000\u0000\u0102D\u0001\u0000\u0000\u0000\u0103\u0104\u0005>"+ - "\u0000\u0000\u0104\u0105\u0005=\u0000\u0000\u0105F\u0001\u0000\u0000\u0000"+ - "\u0106\u0107\u0005<\u0000\u0000\u0107\u0108\u0005=\u0000\u0000\u0108H"+ - "\u0001\u0000\u0000\u0000\u0109\u010a\u0005=\u0000\u0000\u010a\u010b\u0005"+ - "=\u0000\u0000\u010bJ\u0001\u0000\u0000\u0000\u010c\u010d\u0005!\u0000"+ - "\u0000\u010d\u010e\u0005=\u0000\u0000\u010eL\u0001\u0000\u0000\u0000\u010f"+ - "\u0110\u0005.\u0000\u0000\u0110N\u0001\u0000\u0000\u0000\u0111\u0112\u0005"+ - ",\u0000\u0000\u0112P\u0001\u0000\u0000\u0000\u0113\u0114\u0005(\u0000"+ - "\u0000\u0114R\u0001\u0000\u0000\u0000\u0115\u0116\u0005)\u0000\u0000\u0116"+ - "T\u0001\u0000\u0000\u0000\u0117\u0118\u0005{\u0000\u0000\u0118V\u0001"+ - "\u0000\u0000\u0000\u0119\u011a\u0005}\u0000\u0000\u011aX\u0001\u0000\u0000"+ - "\u0000\u011b\u011c\u0005[\u0000\u0000\u011cZ\u0001\u0000\u0000\u0000\u011d"+ - "\u011e\u0005]\u0000\u0000\u011e\\\u0001\u0000\u0000\u0000\u011f\u0120"+ - "\u0005/\u0000\u0000\u0120\u0121\u0005/\u0000\u0000\u0121\u0125\u0001\u0000"+ - "\u0000\u0000\u0122\u0124\b\u0004\u0000\u0000\u0123\u0122\u0001\u0000\u0000"+ - "\u0000\u0124\u0127\u0001\u0000\u0000\u0000\u0125\u0123\u0001\u0000\u0000"+ - "\u0000\u0125\u0126\u0001\u0000\u0000\u0000\u0126\u0128\u0001\u0000\u0000"+ - "\u0000\u0127\u0125\u0001\u0000\u0000\u0000\u0128\u0129\u0006.\u0000\u0000"+ - "\u0129^\u0001\u0000\u0000\u0000\u012a\u012b\u0005/\u0000\u0000\u012b\u012c"+ - "\u0005*\u0000\u0000\u012c\u0130\u0001\u0000\u0000\u0000\u012d\u012f\t"+ - "\u0000\u0000\u0000\u012e\u012d\u0001\u0000\u0000\u0000\u012f\u0132\u0001"+ - "\u0000\u0000\u0000\u0130\u0131\u0001\u0000\u0000\u0000\u0130\u012e\u0001"+ - "\u0000\u0000\u0000\u0131\u0133\u0001\u0000\u0000\u0000\u0132\u0130\u0001"+ - "\u0000\u0000\u0000\u0133\u0134\u0005*\u0000\u0000\u0134\u0135\u0005/\u0000"+ - "\u0000\u0135\u0136\u0001\u0000\u0000\u0000\u0136\u0137\u0006/\u0000\u0000"+ - "\u0137`\u0001\u0000\u0000\u0000\u0138\u013a\u0007\u0005\u0000\u0000\u0139"+ - "\u0138\u0001\u0000\u0000\u0000\u013a\u013b\u0001\u0000\u0000\u0000\u013b"+ - "\u0139\u0001\u0000\u0000\u0000\u013b\u013c\u0001\u0000\u0000\u0000\u013c"+ - "\u013d\u0001\u0000\u0000\u0000\u013d\u013e\u00060\u0000\u0000\u013eb\u0001"+ - "\u0000\u0000\u0000\u000b\u0000\u00c7\u00cc\u00d2\u00d8\u00da\u00e8\u00ee"+ - "\u0125\u0130\u013b\u0001\u0006\u0000\u0000"; - public static final ATN _ATN = - new ATNDeserializer().deserialize(_serializedATN.toCharArray()); - static { - _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; - for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { - _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); - } - } -} \ No newline at end of file From b1e342a353bd66e4275a6b848bb6a4a0f2ecf240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 11:59:55 +0800 Subject: [PATCH 23/54] Delete src/main/java/cod/ast/ASTBuilder.java --- src/main/java/cod/ast/ASTBuilder.java | 629 -------------------------- 1 file changed, 629 deletions(-) delete mode 100644 src/main/java/cod/ast/ASTBuilder.java diff --git a/src/main/java/cod/ast/ASTBuilder.java b/src/main/java/cod/ast/ASTBuilder.java deleted file mode 100644 index 8d700fdc..00000000 --- a/src/main/java/cod/ast/ASTBuilder.java +++ /dev/null @@ -1,629 +0,0 @@ -package cod.ast; - -import static cod.Constants.*; -import cod.ast.nodes.*; -import cod.debug.DebugSystem; -import java.util.*; - -public class ASTBuilder { - private ImportResolver importResolver = new ImportResolver(); - - public ProgramNode build(CoderiveParser.ProgramContext ctx) { - ProgramNode program = ASTFactory.createProgram(); - - // Check if unit declaration exists - if (ctx.unitDeclaration() != null) { - program.unit = buildUnit(ctx.unitDeclaration()); - } else { - // Create a default unit if none exists - program.unit = ASTFactory.createUnit("default"); - } - - // Resolve imports - resolveImports(program.unit); - - for (CoderiveParser.TypeDeclarationContext tctx : ctx.typeDeclaration()) { - program.unit.types.add(buildType(tctx)); - } - - return program; - } - - // Add this method to handle return slot assignment - public StatementNode buildReturnSlotAssignment(CoderiveParser.ReturnSlotAssignmentContext ctx) { - // Extract variable names from assignableList using idList - List variableNames = new ArrayList(); - CoderiveParser.IdListContext idList = ctx.assignableList().idList(); - variableNames.add(idList.ID(0).getText()); - if (idList.ID().size() > 1) variableNames.add(idList.ID(1).getText()); - if (idList.ID().size() > 2) variableNames.add(idList.ID(2).getText()); - - // Extract the slot method call - MethodCallNode methodCall = (MethodCallNode) buildSlotMethodCall(ctx.slotMethodCall()); - - ReturnSlotAssignmentNode assignment = ASTFactory.createReturnSlotAssignment(variableNames, methodCall); - - DebugSystem.debug( - "AST", - "Return slot assignment: " - + assignment.variableNames - + " = " - + assignment.methodCall.slotNames); - return assignment; - } - - private void resolveImports(UnitNode unit) { - if (unit.imports == null || unit.imports.imports.isEmpty()) return; - - DebugSystem.debug("IMPORTS", "Resolving imports for unit: " + unit.name); - - for (String importName : unit.imports.imports) { - try { - ProgramNode importedProgram = importResolver.resolveImport(importName); - // Store resolved imports for later use by interpreter - unit.resolvedImports.put(importName, importedProgram); - DebugSystem.debug("IMPORTS", "Successfully resolved import: " + importName); - } catch (Exception e) { - DebugSystem.error( - "IMPORTS", - "Failed to resolve import: " + importName + " - " + e.getMessage()); - } - } - } - - public UnitNode buildUnit(CoderiveParser.UnitDeclarationContext ctx) { - UnitNode unit = ASTFactory.createUnit(ctx.qualifiedName().getText()); - - // Create GetNode for imports - if (ctx.qualifiedNameList() != null) { - List imports = new ArrayList(); - for (CoderiveParser.QualifiedNameContext q : ctx.qualifiedNameList().qualifiedName()) { - imports.add(q.getText()); - } - unit.imports = ASTFactory.createGetNode(imports); - } - - return unit; - } - - public TypeNode buildType(CoderiveParser.TypeDeclarationContext ctx) { - String visibility = share; - if (ctx.modifiers() != null) { - visibility = ctx.modifiers().getText(); - } - - String extendName = null; - if (ctx.EXTEND() != null && ctx.qualifiedName() != null) { - extendName = ctx.qualifiedName().getText(); - } - - TypeNode type = ASTFactory.createType(ctx.ID().getText(), visibility, extendName); - - for (CoderiveParser.TypeBodyContext tb : ctx.typeBody()) { - ASTNode n = buildTypeBody(tb); - if (n instanceof FieldNode) type.fields.add((FieldNode) n); - else if (n instanceof ConstructorNode) type.constructor = (ConstructorNode) n; - else if (n instanceof MethodNode) type.methods.add((MethodNode) n); - else if (n instanceof StatementNode) type.statements.add((StatementNode) n); - } - - return type; - } - - public FieldNode buildField(CoderiveParser.FieldDeclarationContext ctx) { - FieldNode field = ASTFactory.createField(ctx.ID().getText(), ctx.type().getText()); - if (ctx.expr() != null) { - field.value = buildExpression(ctx.expr()); - } - return field; - } - - public ConstructorNode buildConstructor(CoderiveParser.ConstructorContext ctx) { - ConstructorNode cons = ASTFactory.createConstructor(); - - if (ctx.parameterList() != null) { - for (CoderiveParser.ParameterContext p : ctx.parameterList().parameter()) { - cons.parameters.add(buildParameter(p)); - } - } - for (CoderiveParser.StatementContext s : ctx.statement()) { - cons.body.add(buildStatement(s)); - } - return cons; - } - - public MethodNode buildMethod(CoderiveParser.MethodDeclarationContext ctx) { - String visibility = share; - if (ctx.modifiers() != null) { - visibility = ctx.modifiers().getText(); - } - - List returnSlots = null; - if (ctx.slotList() != null) { - returnSlots = new ArrayList(); - CoderiveParser.IdListContext idList = ctx.slotList().idList(); - returnSlots.add(idList.ID(0).getText()); - if (idList.ID().size() > 1) returnSlots.add(idList.ID(1).getText()); - if (idList.ID().size() > 2) returnSlots.add(idList.ID(2).getText()); - } - - MethodNode method = null; - // method = ASTFactory.createMethod(ctx.ID().getText(), visibility, returnSlots); - - if (ctx.parameterList() != null) { - for (CoderiveParser.ParameterContext p : ctx.parameterList().parameter()) { - method.parameters.add(buildParameter(p)); - } - } - - for (CoderiveParser.StatementContext s : ctx.statement()) { - method.body.add(buildStatement(s)); - } - - return method; - } - - public ExprNode buildUnaryExpr(CoderiveParser.UnaryExprContext ctx) { - String op = ctx.getChild(0).getText(); // Get the unary operator (+ or -) - ExprNode operand = buildExpression(ctx.expr()); // The expression being operated on - return ASTFactory.createUnaryOp(op, operand); - } - - public ParamNode buildParameter(CoderiveParser.ParameterContext ctx) { - return ASTFactory.createParam(ctx.ID().getText(), ctx.type().getText()); - } - - public StatementNode buildInputAssignment(CoderiveParser.InputAssignmentContext ctx) { - String targetType = ctx.inputStatement().typeInput().type().getText(); - String variableName = ctx.assignable().ID().getText(); - return ASTFactory.createInput(targetType, variableName); - } - - public StatementNode buildOutputSlotCall(CoderiveParser.OutputSlotCallContext ctx) { - OutputNode output = ASTFactory.createOutput(); - - // Check if there's slot casting - if (ctx.slotCast() != null) { - // Extract slot names from slotCast - List slotNames = new ArrayList(); - CoderiveParser.IdListContext idList = ctx.slotCast().idList(); - slotNames.add(idList.ID(0).getText()); - if (idList.ID().size() > 1) slotNames.add(idList.ID(1).getText()); - if (idList.ID().size() > 2) slotNames.add(idList.ID(2).getText()); - - // Build method call with slot names - MethodCallNode methodCall = (MethodCallNode) buildMethodCall(ctx.methodCall()); - methodCall.slotNames = slotNames; - output.arguments.add(methodCall); - - DebugSystem.debug("AST", "Output with slot casting: " + slotNames + ":" + methodCall.name); - } else { - // Regular method call without slot casting - MethodCallNode methodCall = (MethodCallNode) buildMethodCall(ctx.methodCall()); - output.arguments.add(methodCall); - } - - return output; -} - - public StatementNode buildOutputNamedAssignment(CoderiveParser.OutputNamedAssignmentContext ctx) { - OutputNode output = ASTFactory.createOutput(ctx.ID().getText()); - // For named assignment, we only add the expression - output.arguments.add(buildExpression(ctx.expr())); - return output; - } - - public StatementNode buildOutputExpression(CoderiveParser.OutputExpressionContext ctx) { - OutputNode output = ASTFactory.createOutput(); - // For simple expressions, we only add the expression itself - output.arguments.add(buildExpression(ctx.expr())); - return output; - } - - // Add this method to handle the new slotMethodCallStatement - public StatementNode buildSlotMethodCallStatement(CoderiveParser.SlotMethodCallStatementContext ctx) { - MethodCallNode call = (MethodCallNode) buildSlotMethodCall(ctx.slotMethodCall()); - return call; // Return as MethodCallNode with slotNames populated - } - - // Update the existing methodCall to handle slot casting - public StatementNode buildMethodCall(CoderiveParser.MethodCallContext ctx) { - // Build the full qualified method name - StringBuilder fullName = new StringBuilder(); - - if (ctx.qualifiedName() != null) { - fullName.append(ctx.qualifiedName().getText()).append("."); - } - fullName.append(ctx.ID().getText()); - - MethodCallNode call = ASTFactory.createMethodCall(ctx.ID().getText(), fullName.toString()); - - if (ctx.argumentList() != null) { - for (CoderiveParser.ExprContext e : ctx.argumentList().expr()) { - call.arguments.add(buildExpression(e)); - } - } - return call; - } - - // Add buildSlotMethodCall method - public StatementNode buildSlotMethodCall(CoderiveParser.SlotMethodCallContext ctx) { - MethodCallNode call = (MethodCallNode) buildMethodCall(ctx.methodCall()); - - // Extract slot names from slotCast using idList - call.slotNames = new ArrayList(); - CoderiveParser.IdListContext idList = ctx.slotCast().idList(); - call.slotNames.add(idList.ID(0).getText()); - if (idList.ID().size() > 1) call.slotNames.add(idList.ID(1).getText()); - if (idList.ID().size() > 2) call.slotNames.add(idList.ID(2).getText()); - - DebugSystem.debug("AST", "Slot method call with slots: " + call.slotNames); - return call; - } - -// FIXED: Use AssignmentNode instead of FieldNode for assignments -public StatementNode buildAssignment(CoderiveParser.AssignmentContext ctx) { - // Regular assignment only - input assignments are handled separately - ExprNode value = buildExpression(ctx.expr()); - ExprNode target; - - if (ctx.assignable().ID() != null) { - // Simple variable assignment: x = value - target = ASTFactory.createIdentifier(ctx.assignable().ID().getText()); - } else { - // Array assignment: arr[0] = value - target = buildIndexAccess(ctx.assignable().indexAccess()); - } - - // Create AssignmentNode instead of FieldNode - return ASTFactory.createAssignment(target, value); -} - - public ExprNode buildTypeCast(CoderiveParser.TypeCastContext ctx) { - String targetType = ctx.type().getText(); - ExprNode expression = buildExpression(ctx.expr()); - return ASTFactory.createTypeCast(targetType, expression); - } - - public ExprNode buildComparisonExpr(CoderiveParser.ComparisonExprContext ctx) { - ExprNode left = buildExpression(ctx.expr(0)); - ExprNode right = buildExpression(ctx.expr(1)); - String op = ctx.getChild(1).getText(); - return ASTFactory.createBinaryOp(left, op, right); - } - - public StatementNode buildForStatement(CoderiveParser.ForStatementContext ctx) { - String iterator = ctx.ID().getText(); - - ExprNode step; - if (ctx.forStepExpr() != null) { - ExprNode stepExpr = buildForStepExpr(ctx.forStepExpr()); - - // If it's an operator step (*2, /2, etc.), create the binary operation - if (stepExpr instanceof UnaryNode) { - UnaryNode unary = (UnaryNode) stepExpr; - ExprNode iteratorRef = ASTFactory.createIdentifier(iterator); - - switch (unary.op) { - case "*": - case "/": - step = ASTFactory.createBinaryOp(iteratorRef, unary.op, unary.operand); - break; - case "+": - step = unary.operand; // +1 becomes just 1 - break; - case "-": - step = unary; // -1 stays as negative literal - break; - default: - step = ASTFactory.createIntLiteral(1); - } - } else { - step = stepExpr; // Regular step expression - } - } else { - step = ASTFactory.createIntLiteral(1); // Default step - } - - ExprNode start = buildExpression(ctx.expr(0)); - ExprNode end = buildExpression(ctx.expr(1)); - - RangeNode range = ASTFactory.createRange(step, start, end); - ForNode forNode = ASTFactory.createFor(iterator, range); - - for (CoderiveParser.StatementContext s : ctx.statement()) { - forNode.body.statements.add(buildStatement(s)); - } - return forNode; -} - -public ExprNode buildForStepExpr(CoderiveParser.ForStepExprContext ctx) { - if (ctx instanceof CoderiveParser.OperatorStepContext) { - return buildOperatorStep((CoderiveParser.OperatorStepContext) ctx); - } else { - return buildExpression(((CoderiveParser.RegularStepContext) ctx).expr()); - } -} - -public ExprNode buildOperatorStep(CoderiveParser.OperatorStepContext ctx) { - String operator = ctx.getChild(0).getText(); // *, /, +, or - - ExprNode operand = buildExpression(ctx.expr()); - - // For the for-loop context, we need to create operations relative to the iterator - // This gets handled in buildForStatement with the iterator context - return ASTFactory.createUnaryOp(operator, operand); -} - - public StatementNode buildIfStatement(CoderiveParser.IfStatementContext ctx) { - DebugSystem.debug("AST", "Building if-elif-else chain..."); - - // 1. Build the root IF node (using expr(0) and thenBlock(0)) - ExprNode ifCondition = buildExpression(ctx.expr(0)); - IfNode rootIfNode = ASTFactory.createIf(ifCondition); - - CoderiveParser.ThenBlockContext ifThenBlock = ctx.thenBlock(0); - for (CoderiveParser.StatementContext stmt : ifThenBlock.statement()) { - rootIfNode.thenBlock.statements.add(buildStatement(stmt)); - } - DebugSystem.debug("AST", "Built root if-block with " + ifThenBlock.statement().size() + " statements"); - - // 2. Keep track of the 'current' node to attach the next 'else' part to. - IfNode currentNode = rootIfNode; - - // 3. Iterate over all ELIF blocks - int elifCount = ctx.ELIF().size(); - for (int i = 0; i < elifCount; i++) { - // ELIF condition is expr(i + 1) - // ELIF block is thenBlock(i + 1) - ExprNode elifCondition = buildExpression(ctx.expr(i + 1)); - CoderiveParser.ThenBlockContext elifThenBlock = ctx.thenBlock(i + 1); - - // Create a new IfNode for the elif - IfNode elifNode = ASTFactory.createIf(elifCondition); - - // Build the elif's then-block - for (CoderiveParser.StatementContext stmt : elifThenBlock.statement()) { - elifNode.thenBlock.statements.add(buildStatement(stmt)); - } - DebugSystem.debug("AST", "Built elif-block #" + (i+1) + " with " + elifThenBlock.statement().size() + " statements"); - - // Add this new elifNode as the single statement inside the - // 'else' block of the *previous* node. - currentNode.elseBlock.statements.add(elifNode); - - // The new elifNode becomes the one we attach the *next* 'else' to. - currentNode = elifNode; - } - - // 4. Check for a final ELSE clause (which could be 'else if' or 'else') - if (ctx.ELSE() != null) { - if (ctx.ifStatement() != null) { - // This is an 'else if' - DebugSystem.debug("AST", "Else contains another if (else-if)"); - StatementNode elseIfNode = buildIfStatement(ctx.ifStatement()); - // Attach the entire 'else if' chain to the last node's elseBlock - currentNode.elseBlock.statements.add(elseIfNode); - } else if (ctx.elseBlock() != null) { - // This is a final 'else' - DebugSystem.debug("AST", "Else contains regular else block"); - for (CoderiveParser.StatementContext stmt : ctx.elseBlock().statement()) { - currentNode.elseBlock.statements.add(buildStatement(stmt)); - } - DebugSystem.debug( - "AST", - "Else-block has " + ctx.elseBlock().statement().size() + " statements"); - } - } - - // Return the head of the entire nested structure - return rootIfNode; - } - - public BlockNode buildThenBlock(CoderiveParser.ThenBlockContext ctx) { - BlockNode block = ASTFactory.createBlock(); - for (CoderiveParser.StatementContext stmt : ctx.statement()) { - block.statements.add(buildStatement(stmt)); - } - return block; - } - - public BlockNode buildElseBlock(CoderiveParser.ElseBlockContext ctx) { - BlockNode block = ASTFactory.createBlock(); - for (CoderiveParser.StatementContext stmt : ctx.statement()) { - block.statements.add(buildStatement(stmt)); - } - return block; - } - - public StatementNode buildVariableDeclaration(CoderiveParser.VariableDeclarationContext ctx) { - if (ctx.VAR() != null) { - VarNode var = ASTFactory.createVar(ctx.ID().getText(), null); - if (ctx.expr() != null) var.value = buildExpression(ctx.expr()); - return var; - } else { - FieldNode f = ASTFactory.createField(ctx.ID().getText(), ctx.type().getText()); - if (ctx.expr() != null) f.value = buildExpression(ctx.expr()); - return f; - } - } - - public ExprNode buildIndexAccess(CoderiveParser.IndexAccessContext ctx) { - // For assignment targets: arr[0] or arr[0][1] - IndexAccessNode current = ASTFactory.createIndexAccess(null, null); - - // Start with the array identifier - current.array = ASTFactory.createIdentifier(ctx.ID().getText()); - - // Handle multiple index expressions - for (int i = 0; i < ctx.expr().size(); i++) { - if (i > 0) { - // Nested index access (multi-dimensional) - IndexAccessNode next = ASTFactory.createIndexAccess(current, null); - next.index = buildExpression(ctx.expr(i)); - current = next; - } else { - // First index - current.index = buildExpression(ctx.expr(i)); - } - } - - return current; - } - - public ExprNode buildIndexAccessExpr(CoderiveParser.IndexAccessExprContext ctx) { - // Handle multiple index accesses like arr[0][1] - ExprNode current = buildAtom(ctx.atom()); - - // ctx.expr() returns the list of index expressions inside the brackets - for (int i = 0; i < ctx.expr().size(); i++) { - IndexAccessNode indexAccess = ASTFactory.createIndexAccess(current, null); - indexAccess.index = buildExpression(ctx.expr(i)); - current = indexAccess; - } - - return current; - } - - public ExprNode buildArrayLiteralExpr(CoderiveParser.ArrayLiteralExprContext ctx) { - List elements = new ArrayList(); - - if (ctx.arrayLiteral().exprList() != null) { - for (CoderiveParser.ExprContext exprCtx : ctx.arrayLiteral().exprList().expr()) { - ExprNode element = buildExpression(exprCtx); - elements.add(element); - } - } - - return ASTFactory.createArray(elements); - } - - // NEW: Handle type with arrays - public ExprNode buildType(CoderiveParser.TypeContext ctx) { - // Build type string including array brackets - StringBuilder typeName = new StringBuilder(); - typeName.append(ctx.simpleType().getText()); - - // Add array brackets for each dimension - for (int i = 0; i < ctx.LBRACKET().size(); i++) { - typeName.append("[]"); - } - - return ASTFactory.createIdentifier(typeName.toString()); - } - - public StatementNode buildExpressionStatement(CoderiveParser.ExpressionStatementContext ctx) { - return (StatementNode) buildExpression(ctx.expr()); - } - - public ExprNode buildPrimaryExpr(CoderiveParser.PrimaryExprContext ctx) { - return buildPrimary(ctx.primary()); - } - - public ExprNode buildAdditiveExpr(CoderiveParser.AdditiveExprContext ctx) { - ExprNode left = buildExpression(ctx.expr(0)); - ExprNode right = buildExpression(ctx.expr(1)); - String op = ctx.getChild(1).getText(); - return ASTFactory.createBinaryOp(left, op, right); - } - - public ExprNode buildMultiplicativeExpr(CoderiveParser.MultiplicativeExprContext ctx) { - ExprNode left = buildExpression(ctx.expr(0)); - ExprNode right = buildExpression(ctx.expr(1)); - String op = ctx.getChild(1).getText(); - return ASTFactory.createBinaryOp(left, op, right); - } - - public ExprNode buildMethodCallExpr(CoderiveParser.MethodCallExprContext ctx) { - return (ExprNode) buildMethodCall(ctx.methodCall()); - } - - public ExprNode buildIdentifierExpr(CoderiveParser.IdentifierExprContext ctx) { - return ASTFactory.createIdentifier(ctx.ID().getText()); - } - - public ExprNode buildIntLiteralExpr(CoderiveParser.IntLiteralExprContext ctx) { - int value = Integer.parseInt(ctx.INT_LIT().getText()); - return ASTFactory.createIntLiteral(value); - } - - public ExprNode buildFloatLiteralExpr(CoderiveParser.FloatLiteralExprContext ctx) { - float value = Float.parseFloat(ctx.FLOAT_LIT().getText()); - return ASTFactory.createFloatLiteral(value); - } - - public ExprNode buildStringLiteralExpr(CoderiveParser.StringLiteralExprContext ctx) { - String value = ctx.STRING_LIT().getText(); - return ASTFactory.createStringLiteral(value); - } - - public ExprNode buildBoolLiteralExpr(CoderiveParser.BoolLiteralExprContext ctx) { - boolean value = Boolean.parseBoolean(ctx.BOOL_LIT().getText()); - return ASTFactory.createBoolLiteral(value); - } - - public ExprNode buildParenthesizedExpr(CoderiveParser.ParenthesizedExprContext ctx) { - return buildExpression(ctx.expr()); - } - - // Helper methods for dispatching - private ASTNode buildTypeBody(CoderiveParser.TypeBodyContext ctx) { - if (ctx.fieldDeclaration() != null) return buildField(ctx.fieldDeclaration()); - if (ctx.constructor() != null) return buildConstructor(ctx.constructor()); - if (ctx.methodDeclaration() != null) return buildMethod(ctx.methodDeclaration()); - if (ctx.statement() != null) return buildStatement(ctx.statement()); - return null; - } - - private StatementNode buildStatement(CoderiveParser.StatementContext ctx) { - if (ctx.variableDeclaration() != null) return buildVariableDeclaration(ctx.variableDeclaration()); - if (ctx.assignment() != null) return buildAssignment(ctx.assignment()); - if (ctx.returnSlotAssignment() != null) return buildReturnSlotAssignment(ctx.returnSlotAssignment()); - if (ctx.inputAssignment() != null) return buildInputAssignment(ctx.inputAssignment()); - if (ctx.methodCallStatement() != null) return buildMethodCall(ctx.methodCallStatement().methodCall()); - if (ctx.outputStatement() != null) return buildOutputStatement(ctx.outputStatement()); - if (ctx.ifStatement() != null) return buildIfStatement(ctx.ifStatement()); - if (ctx.forStatement() != null) return buildForStatement(ctx.forStatement()); - if (ctx.expressionStatement() != null) return buildExpressionStatement(ctx.expressionStatement()); - if (ctx.slotMethodCallStatement() != null) return buildSlotMethodCallStatement(ctx.slotMethodCallStatement()); - return null; - } - - private StatementNode buildOutputStatement(CoderiveParser.OutputStatementContext ctx) { - CoderiveParser.OutputTargetContext target = ctx.outputTarget(); - if (target instanceof CoderiveParser.OutputSlotCallContext) - return buildOutputSlotCall((CoderiveParser.OutputSlotCallContext) target); - if (target instanceof CoderiveParser.OutputNamedAssignmentContext) - return buildOutputNamedAssignment((CoderiveParser.OutputNamedAssignmentContext) target); - if (target instanceof CoderiveParser.OutputExpressionContext) - return buildOutputExpression((CoderiveParser.OutputExpressionContext) target); - return null; - } - - private ExprNode buildExpression(CoderiveParser.ExprContext ctx) { - if (ctx instanceof CoderiveParser.UnaryExprContext) return buildUnaryExpr((CoderiveParser.UnaryExprContext) ctx); - if (ctx instanceof CoderiveParser.MultiplicativeExprContext) return buildMultiplicativeExpr((CoderiveParser.MultiplicativeExprContext) ctx); - if (ctx instanceof CoderiveParser.AdditiveExprContext) return buildAdditiveExpr((CoderiveParser.AdditiveExprContext) ctx); - if (ctx instanceof CoderiveParser.ComparisonExprContext) return buildComparisonExpr((CoderiveParser.ComparisonExprContext) ctx); - if (ctx instanceof CoderiveParser.PrimaryExprContext) return buildPrimaryExpr((CoderiveParser.PrimaryExprContext) ctx); - if (ctx instanceof CoderiveParser.MethodCallExprContext) return buildMethodCallExpr((CoderiveParser.MethodCallExprContext) ctx); - if (ctx instanceof CoderiveParser.TypeCastExprContext) return buildTypeCast((CoderiveParser.TypeCastContext) ((CoderiveParser.TypeCastExprContext) ctx).typeCast()); - return null; - } - - private ExprNode buildPrimary(CoderiveParser.PrimaryContext ctx) { - if (ctx instanceof CoderiveParser.IndexAccessExprContext) return buildIndexAccessExpr((CoderiveParser.IndexAccessExprContext) ctx); - // For other primary types, we need to handle them via the atom - return null; - } - - private ExprNode buildAtom(CoderiveParser.AtomContext ctx) { - if (ctx instanceof CoderiveParser.IdentifierExprContext) return buildIdentifierExpr((CoderiveParser.IdentifierExprContext) ctx); - if (ctx instanceof CoderiveParser.IntLiteralExprContext) return buildIntLiteralExpr((CoderiveParser.IntLiteralExprContext) ctx); - if (ctx instanceof CoderiveParser.FloatLiteralExprContext) return buildFloatLiteralExpr((CoderiveParser.FloatLiteralExprContext) ctx); - if (ctx instanceof CoderiveParser.StringLiteralExprContext) return buildStringLiteralExpr((CoderiveParser.StringLiteralExprContext) ctx); - if (ctx instanceof CoderiveParser.BoolLiteralExprContext) return buildBoolLiteralExpr((CoderiveParser.BoolLiteralExprContext) ctx); - if (ctx instanceof CoderiveParser.ParenthesizedExprContext) return buildParenthesizedExpr((CoderiveParser.ParenthesizedExprContext) ctx); - if (ctx instanceof CoderiveParser.ArrayLiteralExprContext) return buildArrayLiteralExpr((CoderiveParser.ArrayLiteralExprContext) ctx); - return null; - } -} From 396b811c8efe4b27141dd510ac1b8501619e3c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:16:56 +0800 Subject: [PATCH 24/54] Add files via upload --- src/main/java/cod/ast/nodes/ASTNode.java | 16 ++++++---------- .../java/cod/ast/nodes/ArgumentListNode.java | 16 ++++++++++++++++ src/main/java/cod/ast/nodes/ArrayNode.java | 12 +++++++++--- src/main/java/cod/ast/nodes/AssignmentNode.java | 10 +++++++++- src/main/java/cod/ast/nodes/BinaryOpNode.java | 9 +++++++-- src/main/java/cod/ast/nodes/BlockNode.java | 15 +++++++++++---- .../java/cod/ast/nodes/BooleanChainNode.java | 7 +++++++ src/main/java/cod/ast/nodes/ConstructorNode.java | 12 ++++++++++-- 8 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 src/main/java/cod/ast/nodes/ArgumentListNode.java diff --git a/src/main/java/cod/ast/nodes/ASTNode.java b/src/main/java/cod/ast/nodes/ASTNode.java index 3f5357a0..5108bad2 100644 --- a/src/main/java/cod/ast/nodes/ASTNode.java +++ b/src/main/java/cod/ast/nodes/ASTNode.java @@ -1,14 +1,10 @@ // ASTNode.java package cod.ast.nodes; +import cod.ast.ASTVisitor; + public abstract class ASTNode { - protected int line = -1; - protected int column = -1; - - public int getLine() { return line; } - public int getColumn() { return column; } - public void setSourcePosition(int line, int column) { - this.line = line; - this.column = column; - } -} + + public abstract T accept(ASTVisitor visitor); + +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ArgumentListNode.java b/src/main/java/cod/ast/nodes/ArgumentListNode.java new file mode 100644 index 00000000..c9bb585d --- /dev/null +++ b/src/main/java/cod/ast/nodes/ArgumentListNode.java @@ -0,0 +1,16 @@ +// ArgumentListNode.java +package cod.ast.nodes; + +import cod.ast.ASTVisitor; + +import java.util.List; + +public class ArgumentListNode extends ExprNode { + public List arguments; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ArrayNode.java b/src/main/java/cod/ast/nodes/ArrayNode.java index 5058f269..937472db 100644 --- a/src/main/java/cod/ast/nodes/ArrayNode.java +++ b/src/main/java/cod/ast/nodes/ArrayNode.java @@ -1,11 +1,17 @@ package cod.ast.nodes; -import cod.ast.CoderiveParser; +import cod.ast.ASTVisitor; + import java.util.ArrayList; import java.util.List; -import org.antlr.v4.runtime.tree.ParseTree; public class ArrayNode extends ExprNode { public List elements = new ArrayList<>(); - public String elementType; // int[], string[], etc. + public String elementType; // int: [], text: [], etc. + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/src/main/java/cod/ast/nodes/AssignmentNode.java b/src/main/java/cod/ast/nodes/AssignmentNode.java index d07712c6..67a268f6 100644 --- a/src/main/java/cod/ast/nodes/AssignmentNode.java +++ b/src/main/java/cod/ast/nodes/AssignmentNode.java @@ -1,9 +1,11 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + /** * Represents an assignment operation, such as 'x = 5' or 'arr[0] = 10'. */ -public class AssignmentNode extends StatementNode { +public class AssignmentNode extends StmtNode { public ExprNode left; // The target of the assignment (identifier, index access, etc.) public ExprNode right; // The value being assigned @@ -13,4 +15,10 @@ public AssignmentNode(ExprNode left, ExprNode right) { this.left = left; this.right = right; } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/BinaryOpNode.java b/src/main/java/cod/ast/nodes/BinaryOpNode.java index 9674d535..fc39956e 100644 --- a/src/main/java/cod/ast/nodes/BinaryOpNode.java +++ b/src/main/java/cod/ast/nodes/BinaryOpNode.java @@ -1,8 +1,13 @@ package cod.ast.nodes; -import cod.ast.CoderiveParser; -import org.antlr.v4.runtime.tree.ParseTree; +import cod.ast.ASTVisitor; public class BinaryOpNode extends ExprNode { public BinaryOpNode() {} + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/src/main/java/cod/ast/nodes/BlockNode.java b/src/main/java/cod/ast/nodes/BlockNode.java index d78a7ff3..37a0d7ff 100644 --- a/src/main/java/cod/ast/nodes/BlockNode.java +++ b/src/main/java/cod/ast/nodes/BlockNode.java @@ -1,15 +1,22 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + import java.util.ArrayList; import java.util.List; -import org.antlr.v4.runtime.tree.ParseTree; -public class BlockNode extends StatementNode { - public List statements = new ArrayList<>(); +public class BlockNode extends StmtNode { + public List statements = new ArrayList<>(); public BlockNode() {} - public BlockNode(List statements) { + public BlockNode(List statements) { this.statements = statements; } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/src/main/java/cod/ast/nodes/BooleanChainNode.java b/src/main/java/cod/ast/nodes/BooleanChainNode.java index d78d2df3..8c5b2904 100644 --- a/src/main/java/cod/ast/nodes/BooleanChainNode.java +++ b/src/main/java/cod/ast/nodes/BooleanChainNode.java @@ -1,5 +1,6 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; import java.util.*; public class BooleanChainNode extends ExprNode { @@ -9,4 +10,10 @@ public class BooleanChainNode extends ExprNode { public BooleanChainNode() { this.expressions = new ArrayList(); } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ConstructorNode.java b/src/main/java/cod/ast/nodes/ConstructorNode.java index d9a7d35d..f948df3c 100644 --- a/src/main/java/cod/ast/nodes/ConstructorNode.java +++ b/src/main/java/cod/ast/nodes/ConstructorNode.java @@ -1,9 +1,17 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + import java.util.List; import java.util.ArrayList; public class ConstructorNode extends ASTNode { public List parameters = new ArrayList(); - public List body = new ArrayList(); -} + public List body = new ArrayList(); + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file From b31a9d486c3acacfacfab7e9ac157cd5d4daef8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:18:12 +0800 Subject: [PATCH 25/54] Add files via upload --- .../java/cod/ast/nodes/EqualityChainNode.java | 7 ++++++ src/main/java/cod/ast/nodes/ExitNode.java | 13 +++++++++++ src/main/java/cod/ast/nodes/ExprIfNode.java | 22 +++++++++++++++++++ src/main/java/cod/ast/nodes/ExprNode.java | 11 ++++++++-- src/main/java/cod/ast/nodes/FieldNode.java | 15 +++++++++---- src/main/java/cod/ast/nodes/ForNode.java | 12 +++++++--- .../java/cod/ast/nodes/IndexAccessNode.java | 8 ++++++- src/main/java/cod/ast/nodes/InputNode.java | 14 ++++++------ .../java/cod/ast/nodes/MethodCallNode.java | 8 +++++++ 9 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 src/main/java/cod/ast/nodes/ExitNode.java create mode 100644 src/main/java/cod/ast/nodes/ExprIfNode.java diff --git a/src/main/java/cod/ast/nodes/EqualityChainNode.java b/src/main/java/cod/ast/nodes/EqualityChainNode.java index d80d1ece..4a77d0f9 100644 --- a/src/main/java/cod/ast/nodes/EqualityChainNode.java +++ b/src/main/java/cod/ast/nodes/EqualityChainNode.java @@ -1,5 +1,6 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; import java.util.*; public class EqualityChainNode extends ExprNode { @@ -11,4 +12,10 @@ public class EqualityChainNode extends ExprNode { public EqualityChainNode() { this.chainArguments = new ArrayList(); } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ExitNode.java b/src/main/java/cod/ast/nodes/ExitNode.java new file mode 100644 index 00000000..f42acd4d --- /dev/null +++ b/src/main/java/cod/ast/nodes/ExitNode.java @@ -0,0 +1,13 @@ +package cod.ast.nodes; + +import cod.ast.ASTVisitor; + +public class ExitNode extends StmtNode { + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + + +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ExprIfNode.java b/src/main/java/cod/ast/nodes/ExprIfNode.java new file mode 100644 index 00000000..6c1d2ed8 --- /dev/null +++ b/src/main/java/cod/ast/nodes/ExprIfNode.java @@ -0,0 +1,22 @@ +package cod.ast.nodes; + +import cod.ast.ASTVisitor; + +public class ExprIfNode extends ExprNode { + public ExprNode condition; + public ExprNode thenExpr; + public ExprNode elseExpr; + + public ExprIfNode() {} + + public ExprIfNode(ExprNode condition, ExprNode thenExpr, ExprNode elseExpr) { + this.condition = condition; + this.thenExpr = thenExpr; + this.elseExpr = elseExpr; + } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ExprNode.java b/src/main/java/cod/ast/nodes/ExprNode.java index 5c82bf6e..b5cacdda 100644 --- a/src/main/java/cod/ast/nodes/ExprNode.java +++ b/src/main/java/cod/ast/nodes/ExprNode.java @@ -1,13 +1,20 @@ package cod.ast.nodes; -public class ExprNode extends StatementNode { +import cod.ast.ASTVisitor; + +public class ExprNode extends StmtNode { public String name; // For identifiers or method names public Object value; // For literals public String op; // Operator (+, -, *, /, slot_cast, etc.) public ExprNode left; // Left operand public ExprNode right; // Right operand + public boolean isNull = false; public ExprNode() {} - // Remove all ANTLR imports and references + @Override + public T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/FieldNode.java b/src/main/java/cod/ast/nodes/FieldNode.java index 6e47b6a6..33427f4f 100644 --- a/src/main/java/cod/ast/nodes/FieldNode.java +++ b/src/main/java/cod/ast/nodes/FieldNode.java @@ -1,11 +1,18 @@ package cod.ast.nodes; -public class FieldNode extends StatementNode { +import cod.ast.ASTVisitor; +import cod.syntax.Keyword; + +public class FieldNode extends StmtNode { public String name; public String type; - public String visibility; // [FIX] Added visibility property + public Keyword visibility; // [FIX] Added visibility property public ExprNode value; - // The 'left' property for assignments has been removed, - // as the new AssignmentNode is a much cleaner way to handle that. + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + + } diff --git a/src/main/java/cod/ast/nodes/ForNode.java b/src/main/java/cod/ast/nodes/ForNode.java index 2890e025..db227754 100644 --- a/src/main/java/cod/ast/nodes/ForNode.java +++ b/src/main/java/cod/ast/nodes/ForNode.java @@ -1,8 +1,8 @@ package cod.ast.nodes; -import java.util.*; +import cod.ast.ASTVisitor; -public class ForNode extends StatementNode { +public class ForNode extends StmtNode { public String iterator; public RangeNode range; public BlockNode body = new BlockNode(); @@ -13,5 +13,11 @@ public ForNode(String iterator, RangeNode range) { this.iterator = iterator; this.range = range; } - + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + + } diff --git a/src/main/java/cod/ast/nodes/IndexAccessNode.java b/src/main/java/cod/ast/nodes/IndexAccessNode.java index b73f7ab7..bd73275d 100644 --- a/src/main/java/cod/ast/nodes/IndexAccessNode.java +++ b/src/main/java/cod/ast/nodes/IndexAccessNode.java @@ -1,8 +1,14 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + public class IndexAccessNode extends ExprNode { public ExprNode array; public ExprNode index; - // Remove ANTLR import + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/InputNode.java b/src/main/java/cod/ast/nodes/InputNode.java index 5dda2c8a..98ce1d29 100644 --- a/src/main/java/cod/ast/nodes/InputNode.java +++ b/src/main/java/cod/ast/nodes/InputNode.java @@ -1,14 +1,14 @@ package cod.ast.nodes; -import cod.ast.CoderiveParser; -import org.antlr.v4.runtime.tree.ParseTree; +import cod.ast.ASTVisitor; -public class InputNode extends StatementNode { +public class InputNode extends ExprNode { public String targetType; // The type being read (int, string, float, bool) public String variableName; // The variable to assign the input to - @Override - public String toString() { - return "InputNode{type=" + targetType + ", var=" + variableName + "}"; - } + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/MethodCallNode.java b/src/main/java/cod/ast/nodes/MethodCallNode.java index 56a4df74..add3eb2e 100644 --- a/src/main/java/cod/ast/nodes/MethodCallNode.java +++ b/src/main/java/cod/ast/nodes/MethodCallNode.java @@ -1,5 +1,7 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + import java.util.*; public class MethodCallNode extends ExprNode { @@ -9,4 +11,10 @@ public class MethodCallNode extends ExprNode { public String chainType; public List chainArguments; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file From e19141a8fda6c08c4b00a55711b33435bc52b1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:19:09 +0800 Subject: [PATCH 26/54] Add files via upload --- src/main/java/cod/ast/nodes/MethodNode.java | 13 +++++++++++-- .../cod/ast/nodes/MultipleSlotAssignmentNode.java | 10 +++++++++- src/main/java/cod/ast/nodes/OutputNode.java | 12 ++++++++---- src/main/java/cod/ast/nodes/ParamNode.java | 11 +++++++++++ src/main/java/cod/ast/nodes/ProgramNode.java | 8 ++++++++ src/main/java/cod/ast/nodes/RangeNode.java | 11 ++++++++++- .../cod/ast/nodes/ReturnSlotAssignmentNode.java | 11 +++++++++-- src/main/java/cod/ast/nodes/SlotAssignmentNode.java | 10 +++++++++- .../java/cod/ast/nodes/SlotDeclarationNode.java | 10 +++++++++- 9 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/main/java/cod/ast/nodes/MethodNode.java b/src/main/java/cod/ast/nodes/MethodNode.java index bd9a2713..e28f837e 100644 --- a/src/main/java/cod/ast/nodes/MethodNode.java +++ b/src/main/java/cod/ast/nodes/MethodNode.java @@ -3,11 +3,20 @@ import java.util.List; import java.util.ArrayList; +import cod.ast.ASTVisitor; +import cod.syntax.Keyword; + public class MethodNode extends ASTNode { public String name; - public String visibility = "public"; + public Keyword visibility = Keyword.SHARE; public List returnSlots = new ArrayList(); public List parameters = new ArrayList(); - public List body = new ArrayList(); + public List body = new ArrayList(); public boolean isBuiltin = false; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/MultipleSlotAssignmentNode.java b/src/main/java/cod/ast/nodes/MultipleSlotAssignmentNode.java index 01db8ae8..c8e43551 100644 --- a/src/main/java/cod/ast/nodes/MultipleSlotAssignmentNode.java +++ b/src/main/java/cod/ast/nodes/MultipleSlotAssignmentNode.java @@ -1,7 +1,15 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + import java.util.List; -public class MultipleSlotAssignmentNode extends StatementNode { +public class MultipleSlotAssignmentNode extends StmtNode { public List assignments; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/OutputNode.java b/src/main/java/cod/ast/nodes/OutputNode.java index 98d18834..594cf2f6 100644 --- a/src/main/java/cod/ast/nodes/OutputNode.java +++ b/src/main/java/cod/ast/nodes/OutputNode.java @@ -1,12 +1,16 @@ package cod.ast.nodes; -import cod.ast.CoderiveParser; +import cod.ast.ASTVisitor; + import java.util.*; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.TerminalNode; -public class OutputNode extends StatementNode { +public class OutputNode extends StmtNode { public String varName; // optional, for "output n = ..." public List arguments = new ArrayList<>(); // normal output or multiple args + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ParamNode.java b/src/main/java/cod/ast/nodes/ParamNode.java index b9c971da..d243058f 100644 --- a/src/main/java/cod/ast/nodes/ParamNode.java +++ b/src/main/java/cod/ast/nodes/ParamNode.java @@ -1,6 +1,17 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + public class ParamNode extends ASTNode { public String name; public String type; + public ExprNode defaultValue; + public boolean hasDefaultValue = false; + public boolean typeInferred = false; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ProgramNode.java b/src/main/java/cod/ast/nodes/ProgramNode.java index ce748a1f..3da7442b 100644 --- a/src/main/java/cod/ast/nodes/ProgramNode.java +++ b/src/main/java/cod/ast/nodes/ProgramNode.java @@ -1,6 +1,14 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; +import cod.parser.ProgramType; + public class ProgramNode extends ASTNode { public UnitNode unit; + public ProgramType programType; // NEW FIELD + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/RangeNode.java b/src/main/java/cod/ast/nodes/RangeNode.java index 1c1e7f4b..0bd5d4a6 100644 --- a/src/main/java/cod/ast/nodes/RangeNode.java +++ b/src/main/java/cod/ast/nodes/RangeNode.java @@ -1,6 +1,8 @@ package cod.ast.nodes; -public class RangeNode extends ASTNode { +import cod.ast.ASTVisitor; + +public class RangeNode extends ExprNode { public ExprNode step; // NEW: Step comes first now public ExprNode start; // NEW: Start after IN public ExprNode end; // NEW: End after TO @@ -13,4 +15,11 @@ public RangeNode(ExprNode step, ExprNode start, ExprNode end) { this.start = start; this.end = end; } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/ReturnSlotAssignmentNode.java b/src/main/java/cod/ast/nodes/ReturnSlotAssignmentNode.java index b851cff2..5c5feb05 100644 --- a/src/main/java/cod/ast/nodes/ReturnSlotAssignmentNode.java +++ b/src/main/java/cod/ast/nodes/ReturnSlotAssignmentNode.java @@ -1,10 +1,17 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + import java.util.ArrayList; import java.util.List; -import org.antlr.v4.runtime.tree.ParseTree; -public class ReturnSlotAssignmentNode extends StatementNode { +public class ReturnSlotAssignmentNode extends StmtNode { public List variableNames = new ArrayList<>(); public MethodCallNode methodCall; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/src/main/java/cod/ast/nodes/SlotAssignmentNode.java b/src/main/java/cod/ast/nodes/SlotAssignmentNode.java index 785757f8..5515e4dc 100644 --- a/src/main/java/cod/ast/nodes/SlotAssignmentNode.java +++ b/src/main/java/cod/ast/nodes/SlotAssignmentNode.java @@ -1,6 +1,14 @@ package cod.ast.nodes; -public class SlotAssignmentNode extends StatementNode { +import cod.ast.ASTVisitor; + +public class SlotAssignmentNode extends StmtNode { public String slotName; public ExprNode value; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/SlotDeclarationNode.java b/src/main/java/cod/ast/nodes/SlotDeclarationNode.java index e233b254..e235e9b0 100644 --- a/src/main/java/cod/ast/nodes/SlotDeclarationNode.java +++ b/src/main/java/cod/ast/nodes/SlotDeclarationNode.java @@ -1,8 +1,16 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + import java.util.ArrayList; import java.util.List; -public class SlotDeclarationNode extends StatementNode { +public class SlotDeclarationNode extends StmtNode { public List slotNames = new ArrayList<>(); + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file From 6637c7fd8faba8f8e079965da1826c9b51d3a766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:19:59 +0800 Subject: [PATCH 27/54] Add files via upload --- src/main/java/cod/ast/nodes/SlotNode.java | 8 +++++++ src/main/java/cod/ast/nodes/StmtIfNode.java | 21 +++++++++++++++++++ src/main/java/cod/ast/nodes/StmtNode.java | 7 +++++++ src/main/java/cod/ast/nodes/TupleNode.java | 14 +++++++++++++ src/main/java/cod/ast/nodes/TypeCastNode.java | 13 ++++++------ src/main/java/cod/ast/nodes/TypeNode.java | 13 +++++++++--- src/main/java/cod/ast/nodes/UnaryNode.java | 8 ++++++- src/main/java/cod/ast/nodes/UnitNode.java | 11 +++++++--- src/main/java/cod/ast/nodes/UseNode.java | 16 ++++++++++++++ src/main/java/cod/ast/nodes/VarNode.java | 10 ++++++++- 10 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 src/main/java/cod/ast/nodes/StmtIfNode.java create mode 100644 src/main/java/cod/ast/nodes/StmtNode.java create mode 100644 src/main/java/cod/ast/nodes/TupleNode.java create mode 100644 src/main/java/cod/ast/nodes/UseNode.java diff --git a/src/main/java/cod/ast/nodes/SlotNode.java b/src/main/java/cod/ast/nodes/SlotNode.java index a81970a0..c1ee2c2d 100644 --- a/src/main/java/cod/ast/nodes/SlotNode.java +++ b/src/main/java/cod/ast/nodes/SlotNode.java @@ -1,5 +1,7 @@ package cod.ast.nodes; +import cod.ast.ASTVisitor; + public class SlotNode extends ASTNode { public String name; public String type; @@ -10,4 +12,10 @@ public boolean isNamed() { // If name starts with digit, it's auto-generated (since IDs can't start with digit) return !Character.isDigit(name.charAt(0)); } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/StmtIfNode.java b/src/main/java/cod/ast/nodes/StmtIfNode.java new file mode 100644 index 00000000..ace6c96e --- /dev/null +++ b/src/main/java/cod/ast/nodes/StmtIfNode.java @@ -0,0 +1,21 @@ +package cod.ast.nodes; + +import cod.ast.ASTVisitor; + +public class StmtIfNode extends StmtNode { + public ExprNode condition; + public BlockNode thenBlock = new BlockNode(); + public BlockNode elseBlock = new BlockNode(); + + public StmtIfNode() {} + + public StmtIfNode(ExprNode condition) { + this.condition = condition; + } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/StmtNode.java b/src/main/java/cod/ast/nodes/StmtNode.java new file mode 100644 index 00000000..db55567a --- /dev/null +++ b/src/main/java/cod/ast/nodes/StmtNode.java @@ -0,0 +1,7 @@ +package cod.ast.nodes; + +// StatementNode + +public abstract class StmtNode extends ASTNode { + +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/TupleNode.java b/src/main/java/cod/ast/nodes/TupleNode.java new file mode 100644 index 00000000..a6dbdeb8 --- /dev/null +++ b/src/main/java/cod/ast/nodes/TupleNode.java @@ -0,0 +1,14 @@ +package cod.ast.nodes; + +import cod.ast.ASTVisitor; +import java.util.List; + +public class TupleNode extends ExprNode { + public List elements; + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/TypeCastNode.java b/src/main/java/cod/ast/nodes/TypeCastNode.java index bfa23dbd..f244abd2 100644 --- a/src/main/java/cod/ast/nodes/TypeCastNode.java +++ b/src/main/java/cod/ast/nodes/TypeCastNode.java @@ -1,15 +1,14 @@ package cod.ast.nodes; -import cod.ast.ASTBuilder; -import cod.ast.CoderiveParser; -import org.antlr.v4.runtime.tree.ParseTree; +import cod.ast.ASTVisitor; public class TypeCastNode extends ExprNode { public String targetType; // The target type to cast to public ExprNode expression; // The expression being cast - @Override - public String toString() { - return "TypeCastNode{type=" + targetType + ", expr=" + expression + "}"; - } + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/TypeNode.java b/src/main/java/cod/ast/nodes/TypeNode.java index 8846b361..38304794 100644 --- a/src/main/java/cod/ast/nodes/TypeNode.java +++ b/src/main/java/cod/ast/nodes/TypeNode.java @@ -3,15 +3,22 @@ import java.util.List; import java.util.ArrayList; -import static cod.Constants.*; +import cod.ast.ASTVisitor; +import cod.syntax.Keyword; public class TypeNode extends ASTNode { public String name; - public String visibility = share; + public Keyword visibility = Keyword.SHARE; public String extendName = null; public List fields = new ArrayList(); public ConstructorNode constructor; public List methods = new ArrayList(); - public List statements = new ArrayList(); + public List statements = new ArrayList(); + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/UnaryNode.java b/src/main/java/cod/ast/nodes/UnaryNode.java index 28f029fb..36ea01dc 100644 --- a/src/main/java/cod/ast/nodes/UnaryNode.java +++ b/src/main/java/cod/ast/nodes/UnaryNode.java @@ -1,6 +1,6 @@ package cod.ast.nodes; -import org.antlr.v4.runtime.tree.ParseTree; +import cod.ast.ASTVisitor; public class UnaryNode extends ExprNode { public String op; // "+" or "-" @@ -12,4 +12,10 @@ public UnaryNode(String op, ExprNode operand) { this.op = op; this.operand = operand; } + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/UnitNode.java b/src/main/java/cod/ast/nodes/UnitNode.java index 7ce9211e..a3c450d3 100644 --- a/src/main/java/cod/ast/nodes/UnitNode.java +++ b/src/main/java/cod/ast/nodes/UnitNode.java @@ -1,18 +1,23 @@ package cod.ast.nodes; -import cod.ast.CoderiveParser; +import cod.ast.ASTVisitor; + import java.util.List; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import org.antlr.v4.runtime.tree.ParseTree; public class UnitNode extends ASTNode { public String name; - public GetNode imports; // CHANGED: from List to GetNode + public UseNode imports; // CHANGED: from List to UseNode public List types = new ArrayList(); // Add this field for resolved imports public Map resolvedImports = new HashMap(); + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/UseNode.java b/src/main/java/cod/ast/nodes/UseNode.java new file mode 100644 index 00000000..2b0ee4eb --- /dev/null +++ b/src/main/java/cod/ast/nodes/UseNode.java @@ -0,0 +1,16 @@ +package cod.ast.nodes; + +import cod.ast.ASTVisitor; + +import java.util.ArrayList; +import java.util.List; + +public class UseNode extends ASTNode { + public List imports = new ArrayList<>(); + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/src/main/java/cod/ast/nodes/VarNode.java b/src/main/java/cod/ast/nodes/VarNode.java index 5585d102..177a7f24 100644 --- a/src/main/java/cod/ast/nodes/VarNode.java +++ b/src/main/java/cod/ast/nodes/VarNode.java @@ -1,8 +1,16 @@ package cod.ast.nodes; -public class VarNode extends StatementNode { +import cod.ast.ASTVisitor; + +public class VarNode extends StmtNode { public String name; public ExprNode value; public String explicitType; // <<< ADDED THIS FIELD + + @Override + public final T accept(ASTVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file From 83f4ca480e604a523f5d300be0be87d755cc1c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:20:34 +0800 Subject: [PATCH 28/54] Delete src/main/java/cod/ast/nodes/StatementNode.java --- src/main/java/cod/ast/nodes/StatementNode.java | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/main/java/cod/ast/nodes/StatementNode.java diff --git a/src/main/java/cod/ast/nodes/StatementNode.java b/src/main/java/cod/ast/nodes/StatementNode.java deleted file mode 100644 index 45ed2220..00000000 --- a/src/main/java/cod/ast/nodes/StatementNode.java +++ /dev/null @@ -1,6 +0,0 @@ -package cod.ast.nodes; - -// StatementNode.java - -public class StatementNode extends ASTNode { -} \ No newline at end of file From 4fc4fb3793fdd24146db001abc48cdbd80347522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:21:01 +0800 Subject: [PATCH 29/54] Delete src/main/java/cod/ast/nodes/IfNode.java --- src/main/java/cod/ast/nodes/IfNode.java | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/main/java/cod/ast/nodes/IfNode.java diff --git a/src/main/java/cod/ast/nodes/IfNode.java b/src/main/java/cod/ast/nodes/IfNode.java deleted file mode 100644 index d37261a4..00000000 --- a/src/main/java/cod/ast/nodes/IfNode.java +++ /dev/null @@ -1,17 +0,0 @@ -package cod.ast.nodes; - -import java.util.*; - -public class IfNode extends StatementNode { - public ExprNode condition; - public BlockNode thenBlock = new BlockNode(); - public BlockNode elseBlock = new BlockNode(); - - public IfNode() {} - - public IfNode(ExprNode condition) { - this.condition = condition; - } - - // Remove ANTLR imports and references -} \ No newline at end of file From 387441ff47ff8cd6e9bea2e0dfdac5c8e81c55dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:21:27 +0800 Subject: [PATCH 30/54] Delete src/main/java/cod/ast/nodes/GetNode.java --- src/main/java/cod/ast/nodes/GetNode.java | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/main/java/cod/ast/nodes/GetNode.java diff --git a/src/main/java/cod/ast/nodes/GetNode.java b/src/main/java/cod/ast/nodes/GetNode.java deleted file mode 100644 index 1bae2b20..00000000 --- a/src/main/java/cod/ast/nodes/GetNode.java +++ /dev/null @@ -1,10 +0,0 @@ -package cod.ast.nodes; - -import cod.ast.CoderiveParser; -import java.util.ArrayList; -import java.util.List; -import org.antlr.v4.runtime.tree.ParseTree; - -public class GetNode extends ASTNode { - public List imports = new ArrayList<>(); -} \ No newline at end of file From 7012259720e67ecab7323f1d7fbbaed9b735d03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:25:42 +0800 Subject: [PATCH 31/54] Add files via upload --- src/main/java/cod/ast/ASTFactory.java | 120 ++- src/main/java/cod/ast/ASTPrinter.java | 673 ++++++++++------ src/main/java/cod/ast/ASTVisitor.java | 54 ++ src/main/java/cod/ast/BaseASTVisitor.java | 205 +++++ src/main/java/cod/ast/ConstantFolder.java | 720 ++++++++++++++++++ .../java/cod/ast/ExpressionFlattener.java | 341 +++++++++ src/main/java/cod/ast/OptimizationStats.java | 54 ++ src/main/java/cod/ast/Optimizer.java | 88 +++ 8 files changed, 1996 insertions(+), 259 deletions(-) create mode 100644 src/main/java/cod/ast/ASTVisitor.java create mode 100644 src/main/java/cod/ast/BaseASTVisitor.java create mode 100644 src/main/java/cod/ast/ConstantFolder.java create mode 100644 src/main/java/cod/ast/ExpressionFlattener.java create mode 100644 src/main/java/cod/ast/OptimizationStats.java create mode 100644 src/main/java/cod/ast/Optimizer.java diff --git a/src/main/java/cod/ast/ASTFactory.java b/src/main/java/cod/ast/ASTFactory.java index c3cfc12d..b08bf9a3 100644 --- a/src/main/java/cod/ast/ASTFactory.java +++ b/src/main/java/cod/ast/ASTFactory.java @@ -1,7 +1,11 @@ package cod.ast; import cod.ast.nodes.*; + +import cod.syntax.Keyword; + import java.util.*; +import java.math.BigDecimal; public class ASTFactory { @@ -12,26 +16,26 @@ public static ProgramNode createProgram() { public static UnitNode createUnit(String name) { UnitNode unit = new UnitNode(); unit.name = name; - unit.imports = new GetNode(); + unit.imports = new UseNode(); unit.types = new ArrayList(); unit.resolvedImports = new HashMap(); return unit; } - public static GetNode createGetNode(List imports) { - GetNode getNode = new GetNode(); - getNode.imports = imports; - return getNode; + public static UseNode createUseNode(List imports) { + UseNode useNode = new UseNode(); + useNode.imports = imports; + return useNode; } - public static TypeNode createType(String name, String visibility, String extendName) { + public static TypeNode createType(String name, Keyword visibility, String extendName) { TypeNode type = new TypeNode(); type.name = name; type.visibility = visibility; type.extendName = extendName; type.fields = new ArrayList(); type.methods = new ArrayList(); - type.statements = new ArrayList(); + type.statements = new ArrayList(); return type; } @@ -42,16 +46,11 @@ public static FieldNode createField(String name, String type, ExprNode value) { field.value = value; return field; } - - public static FieldNode createField(String name, String type) { - return createField(name, type, null); - } - public static FieldNode createFieldWithVisibility(String name, String type, String visibility) { + public static FieldNode createField(String name, String type) { FieldNode field = new FieldNode(); field.name = name; field.type = type; - field.visibility = visibility; return field; } @@ -65,26 +64,31 @@ public static AssignmentNode createAssignment(ExprNode target, ExprNode value) { public static ConstructorNode createConstructor() { ConstructorNode cons = new ConstructorNode(); cons.parameters = new ArrayList(); - cons.body = new ArrayList(); + cons.body = new ArrayList(); return cons; } - public static MethodNode createMethod(String name, String visibility, List returnSlots) { + public static MethodNode createMethod(String name, Keyword visibility, List returnSlots) { MethodNode method = new MethodNode(); method.name = name; method.visibility = visibility; method.returnSlots = returnSlots != null ? returnSlots : new ArrayList(); method.parameters = new ArrayList(); - method.body = new ArrayList(); + method.body = new ArrayList(); return method; } - public static ParamNode createParam(String name, String type) { - ParamNode param = new ParamNode(); - param.name = name; - param.type = type; - return param; +public static ParamNode createParam(String name, String type, ExprNode defaultValue, boolean typeInferred) { + ParamNode param = new ParamNode(); + param.name = name; + param.type = type; + if (defaultValue != null) { + param.defaultValue = defaultValue; + param.hasDefaultValue = true; } + param.typeInferred = typeInferred; + return param; +} public static SlotNode createSlot(String type, String name) { SlotNode slot = new SlotNode(); @@ -105,21 +109,34 @@ public static ExprNode createIntLiteral(int value) { return node; } - public static ExprNode createFloatLiteral(float value) { + public static ExprNode createLongLiteral(long value) { + ExprNode node = new ExprNode(); + node.value = value; + return node; +} + + public static ExprNode createFloatLiteral(BigDecimal value) { + ExprNode node = new ExprNode(); + node.value = value; // Stores the precise BigDecimal object + return node; +} + + public static ExprNode createStringLiteral(String value) { ExprNode node = new ExprNode(); node.value = value; return node; } - public static ExprNode createStringLiteral(String value) { + public static ExprNode createBoolLiteral(boolean value) { ExprNode node = new ExprNode(); node.value = value; return node; } - public static ExprNode createBoolLiteral(boolean value) { + public static ExprNode createNullLiteral() { ExprNode node = new ExprNode(); - node.value = value; + node.value = null; + node.isNull = true; return node; } @@ -140,13 +157,12 @@ public static EqualityChainNode createEqualityChain(ExprNode left, String operat return chain; } - public static BooleanChainNode createBooleanChain(boolean isAll, List expressions) { + public static BooleanChainNode createBooleanChain(boolean isAll, List expressions) { BooleanChainNode node = new BooleanChainNode(); node.isAll = isAll; node.expressions = expressions != null ? expressions : new ArrayList(); return node; } - public static UnaryNode createUnaryOp(String op, ExprNode operand) { UnaryNode node = new UnaryNode(); @@ -164,7 +180,7 @@ public static TypeCastNode createTypeCast(String targetType, ExprNode expression public static SlotAssignmentNode createImplicitReturn(ExprNode returnExpr) { SlotAssignmentNode returnStmt = new SlotAssignmentNode(); - returnStmt.slotName = "return"; + returnStmt.slotName = "_"; returnStmt.value = returnExpr; return returnStmt; } @@ -190,6 +206,12 @@ public static ArrayNode createArray() { return createArray(null); } + public static TupleNode createTuple(List elements) { + TupleNode node = new TupleNode(); + node.elements = elements != null ? elements : new ArrayList(); + return node; + } + public static IndexAccessNode createIndexAccess(ExprNode array, ExprNode index) { IndexAccessNode node = new IndexAccessNode(); node.array = array; @@ -197,12 +219,20 @@ public static IndexAccessNode createIndexAccess(ExprNode array, ExprNode index) return node; } - public static IfNode createIf(ExprNode condition) { - IfNode ifNode = new IfNode(); - ifNode.condition = condition; - ifNode.thenBlock = new BlockNode(); - ifNode.elseBlock = new BlockNode(); - return ifNode; + public static ExprIfNode createIfExpression(ExprNode condition, ExprNode thenExpr, ExprNode elseExpr) { + ExprIfNode node = new ExprIfNode(); + node.condition = condition; + node.thenExpr = thenExpr; + node.elseExpr = elseExpr; + return node; +} + + public static StmtIfNode createIfStatement(ExprNode condition) { + StmtIfNode stmtIfNode = new StmtIfNode(); + stmtIfNode.condition = condition; + stmtIfNode.thenBlock = new BlockNode(); + stmtIfNode.elseBlock = new BlockNode(); + return stmtIfNode; } public static ForNode createFor(String iterator, RangeNode range) { @@ -213,19 +243,15 @@ public static ForNode createFor(String iterator, RangeNode range) { return forNode; } - public static RangeNode createRange(ExprNode step, ExprNode start, ExprNode end) { - RangeNode range = new RangeNode(); - range.step = step; - range.start = start; - range.end = end; - return range; - } +public static RangeNode createRange(ExprNode step, ExprNode start, ExprNode end) { + return new RangeNode(step, start, end); +} public static BlockNode createBlock() { return new BlockNode(); } - public static BlockNode createBlock(List statements) { + public static BlockNode createBlock(List statements) { return new BlockNode(statements); } @@ -254,6 +280,16 @@ public static OutputNode createOutput() { return createOutput(null); } + public static ExitNode createExit() { + return new ExitNode(); + } + + public static ArgumentListNode createArgumentList(List arguments) { + ArgumentListNode node = new ArgumentListNode(); + node.arguments = arguments != null ? arguments : new ArrayList(); + return node; + } + public static ReturnSlotAssignmentNode createReturnSlotAssignment(List variableNames, MethodCallNode methodCall) { ReturnSlotAssignmentNode assignment = new ReturnSlotAssignmentNode(); assignment.variableNames = variableNames; diff --git a/src/main/java/cod/ast/ASTPrinter.java b/src/main/java/cod/ast/ASTPrinter.java index 21b23636..270d85c4 100644 --- a/src/main/java/cod/ast/ASTPrinter.java +++ b/src/main/java/cod/ast/ASTPrinter.java @@ -1,237 +1,476 @@ package cod.ast; +import static cod.syntax.Keyword.*; import cod.ast.nodes.*; -public class ASTPrinter { - - public static void print(ASTNode node, int indent) { - if (node == null) return; - String pad = new String(new char[indent]).replace("\0", " "); - - if (node instanceof ProgramNode) { - System.out.println(pad + "Program"); - print(((ProgramNode) node).unit, indent + 1); - - } else if (node instanceof UnitNode) { - UnitNode u = (UnitNode) node; - System.out.println(pad + "Unit: " + u.name); - // Print GetNode if it exists - if (u.imports != null) { - print(u.imports, indent + 1); - } - for (TypeNode t : u.types) print(t, indent + 1); - - } else if (node instanceof GetNode) { - GetNode get = (GetNode) node; - if (get.imports.isEmpty()) { - System.out.println(pad + "Get imports: []"); - } else { - System.out.println(pad + "Get imports: " + get.imports); - } - - } else if (node instanceof TypeNode) { - TypeNode t = (TypeNode) node; - System.out.println( - pad - + "Class: " - + t.name - + " Extends: " - + t.extendName - + " Visibility: " - + t.visibility); - for (FieldNode f : t.fields) print(f, indent + 1); - if (t.constructor != null) print(t.constructor, indent + 1); - for (MethodNode m : t.methods) print(m, indent + 1); - for (StatementNode s : t.statements) print(s, indent + 1); - - } else if (node instanceof FieldNode) { - FieldNode f = (FieldNode) node; - System.out.println(pad + "Field: " + f.type + " " + f.name + " Visibility: " + f.visibility); - if (f.value != null) { - System.out.print(pad + " Value: "); - print(f.value, indent + 2); - } - // REMOVED: Array assignment handling from FieldNode since it's now in AssignmentNode - - } else if (node instanceof AssignmentNode) { - // NEW: Handle AssignmentNode - AssignmentNode assignment = (AssignmentNode) node; - System.out.println(pad + "Assignment:"); - System.out.print(pad + " Target: "); - print(assignment.left, indent + 2); - System.out.print(pad + " Value: "); - print(assignment.right, indent + 2); - - } else if (node instanceof ConstructorNode) { - ConstructorNode c = (ConstructorNode) node; - System.out.println(pad + "Constructor Params: " + c.parameters.size()); - for (ParamNode p : c.parameters) print(p, indent + 1); - for (StatementNode s : c.body) print(s, indent + 1); - - } else if (node instanceof MethodNode) { - MethodNode m = (MethodNode) node; - System.out.print(pad + "Method: " + m.name + " Slots: "); - for (SlotNode s : m.returnSlots) System.out.print(s.name + " "); - System.out.println(" Visibility: " + m.visibility); - for (ParamNode p : m.parameters) print(p, indent + 1); - for (StatementNode s : m.body) print(s, indent + 1); - - } else if (node instanceof MethodCallNode) { - MethodCallNode mc = (MethodCallNode) node; - System.out.print( - pad - + "Identifier/Call: " - + (mc.qualifiedName != null ? mc.qualifiedName : mc.name)); - // FIX: Handle multiple slot names - if (mc.slotNames != null && !mc.slotNames.isEmpty()) { - System.out.print(" (slot_cast: "); - for (int i = 0; i < mc.slotNames.size(); i++) { - if (i > 0) System.out.print(", "); - System.out.print(mc.slotNames.get(i)); - } - System.out.print(")"); - } +public class ASTPrinter extends BaseASTVisitor { + private int indent = 0; + + private String getIndent() { + return new String(new char[indent]).replace("\0", "| "); + } + + private void print(String message) { + System.out.print(getIndent() + message); + } + + private void println(String message) { + print(getIndent() + message + "\n"); + } + + @Override + public Void visit(ProgramNode node) { + println("\nPROGRAM"); + println("| "); + if (node.unit != null) visit(node.unit); + return null; + } + + @Override + public Void visit(UnitNode node) { + println("| UNIT: " + node.name); + + if (node.imports != null) visit(node.imports); + visitAll(node.types); + println("| "); + return null; + } + + @Override + public Void visit(UseNode node) { + println("USE imports: " + (node.imports.isEmpty() ? "[]" : node.imports)); + println("| "); + return null; + } + + @Override + public Void visit(TypeNode node) { + println("CLASS: " + node.name + " extends: " + node.extendName + " visibility: " + node.visibility + "\n| | "); + indent++; + visitAll(node.fields); + if (node.constructor != null) visit(node.constructor); + visitAll(node.methods); + visitAll(node.statements); + indent--; + return null; + } + + @Override + public Void visit(FieldNode node) { + println("FIELD: " + node.type + " " + node.name + " visibility: " + node.visibility); + if (node.value != null) { + println("| value:"); + indent += 2; + visit(node.value); + indent -= 2; + } + return null; + } + + @Override + public Void visit(MethodNode node) { + print("| METHOD: " + node.name + " slots: "); + for (SlotNode s : node.returnSlots) System.out.print(s.name + " "); + System.out.println(" visibility: " + node.visibility); + visitAll(node.parameters); + visitAll(node.body); + return null; + } + + @Override + public Void visit(ParamNode node) { + println("| PARAM: " + node.type + " " + node.name); + return null; + } + + @Override + public Void visit(ConstructorNode node) { + println("CONSTRUCTOR PARAMS: " + node.parameters.size()); + indent++; + visitAll(node.parameters); + visitAll(node.body); + indent--; + return null; + } + + @Override + public Void visit(BlockNode node) { + println("BLOCK:"); + indent++; + visitAll(node.statements); + indent--; + return null; + } + + @Override + public Void visit(AssignmentNode node) { + println("ASSIGNMENT:"); + println("| target:"); + indent += 2; + if (node.left != null) visit(node.left); + indent -= 2; + println("| value:"); + indent += 2; + if (node.right != null) visit(node.right); + indent -= 2; + return null; + } + + @Override + public Void visit(VarNode node) { + print("VAR: " + node.name); + if (node.explicitType != null) { + System.out.print(" (type: " + node.explicitType + ")"); + } + if (node.value != null) { + System.out.println(" ="); + indent++; + visit(node.value); + indent--; + } else { System.out.println(); - for (ExprNode arg : mc.arguments) print(arg, indent + 1); - + } + return null; + } + + @Override + public Void visit(StmtIfNode node) { + println("| | IF condition:"); + indent ++; + if (node.condition != null) visit(node.condition); + indent --; + println("| | | THEN execute:"); + indent += 2; + if (node.thenBlock != null) visit(node.thenBlock); + indent -= 2; + if (node.elseBlock != null && !node.elseBlock.statements.isEmpty()) { + println("| | ELSE:"); + indent += 2; + visit(node.elseBlock); + indent -= 2; + } + return null; + } + + @Override + public Void visit(ForNode node) { + println("FOR iterator: " + node.iterator); + indent += 2; + if (node.range != null) visit(node.range); + indent -= 2; + println("| BODY:"); + indent += 2; + if (node.body != null) visit(node.body); + indent -= 2; + return null; + } + + @Override + public Void visit(RangeNode node) { + println("| step:"); + indent += 2; + if (node.step != null) visit(node.step); + indent -= 2; + println("RANGE:"); + println("| start:"); + indent += 2; + if (node.start != null) visit(node.start); + indent -= 2; + println("| end:"); + indent += 2; + if (node.end != null) visit(node.end); + indent -= 2; + return null; + } + + @Override + public Void visit(OutputNode node) { + print("OUTPUT"); + if (node.varName != null) System.out.print(" var: " + node.varName); + System.out.println(); + + if (node.arguments.isEmpty()) { + println("| (no arguments)"); + } else { + for (int i = 0; i < node.arguments.size(); i++) { + println("| ARGUMENT " + i + ":"); + indent += 2; + visit(node.arguments.get(i)); + indent -= 2; + } + } + return null; + } + + @Override + public Void visit(InputNode node) { + println("INPUT: " + node.variableName + " = (" + node.targetType + ") input"); + return null; + } + + @Override + public Void visit(ExitNode node) { + println("EXIT"); + return null; + } + + @Override + public Void visit(ReturnSlotAssignmentNode node) { + println("RETURN SLOT ASSIGNMENT:"); + println("| VARIABLES: " + node.variableNames); + println("| METHOD CALL:"); + indent += 2; + if (node.methodCall != null) visit(node.methodCall); + indent -= 2; + return null; + } + + @Override + public Void visit(SlotDeclarationNode node) { + println("SLOT DECLARATION: " + node.slotNames); + return null; + } + + @Override + public Void visit(SlotAssignmentNode node) { + println("SLOT ASSIGNMENT:"); + println("| slot: " + (node.slotName != null ? node.slotName : "(implicit)")); + println("| value:"); + indent += 2; + if (node.value != null) visit(node.value); + indent -= 2; + return null; + } + + @Override + public Void visit(MultipleSlotAssignmentNode node) { + println("MULTIPLE SLOT ASSIGNMENT:"); + indent++; + for (int i = 0; i < node.assignments.size(); i++) { + SlotAssignmentNode assign = node.assignments.get(i); + println("ASSIGNMENT " + i + ":"); + println("| slot: " + (assign.slotName != null ? assign.slotName : "(positional)")); + println("| value:"); + indent += 2; + if (assign.value != null) visit(assign.value); + indent -= 2; + } + indent--; + return null; + } + + @Override + public Void visit(ExprNode node) { + // Check if this ExprNode is actually a more specific type (like in original printer) + if (node instanceof IndexAccessNode) { + // Handle IndexAccessNode that got cast to ExprNode + IndexAccessNode idx = (IndexAccessNode) node; + println("INDEX ACCESS"); + println("| array:"); + indent += 2; + visit(idx.array); + indent -= 2; + println("| index:"); + indent += 2; + visit(idx.index); + indent -= 2; } else if (node instanceof ArrayNode) { + // Handle ArrayNode that got cast to ExprNode ArrayNode arr = (ArrayNode) node; - System.out.println(pad + "ArrayLiteral with " + arr.elements.size() + " elements:"); + println("ARRAY literal with " + arr.elements.size() + " elements:"); + indent++; for (int i = 0; i < arr.elements.size(); i++) { - System.out.print(pad + " [" + i + "]: "); - print(arr.elements.get(i), indent + 2); + println("[" + i + "]:"); + indent++; + visit(arr.elements.get(i)); + indent--; } - - } else if (node instanceof IndexAccessNode) { - IndexAccessNode idx = (IndexAccessNode) node; - System.out.println(pad + "IndexAccess"); - System.out.print(pad + " Array: "); - print(idx.array, indent + 2); - System.out.print(pad + " Index: "); - print(idx.index, indent + 2); - + indent--; + } else if (node instanceof BooleanChainNode) { + // Handle BooleanChainNode that got cast to ExprNode + BooleanChainNode chain = (BooleanChainNode) node; + println("BOOLEAN chain: " + (chain.isAll ? ALL : ANY)); + indent++; + for (ExprNode expr : chain.expressions) { + visit(expr); + } + indent--; + } else if (node instanceof EqualityChainNode) { + // Handle EqualityChainNode that got cast to ExprNode + EqualityChainNode chain = (EqualityChainNode) node; + println("EQUALITY chain: " + (chain.isAllChain ? ALL : ANY) + " " + chain.operator); + println("| LEFT:"); + indent += 2; + visit(chain.left); + indent -= 2; + println("| CHAIN arguments:"); + indent += 2; + for (ExprNode arg : chain.chainArguments) { + visit(arg); + } + indent -= 2; } else if (node instanceof UnaryNode) { + // Handle UnaryNode that got cast to ExprNode UnaryNode unary = (UnaryNode) node; - System.out.println(pad + "Unary: " + unary.op); - print(unary.operand, indent + 1); - - } else if (node instanceof BinaryOpNode) { - BinaryOpNode b = (BinaryOpNode) node; - System.out.println(pad + "BinaryOp: " + b.op); - if (b.left != null) print(b.left, indent + 1); - if (b.right != null) print(b.right, indent + 1); - - } else if (node instanceof ExprNode) { - ExprNode e = (ExprNode) node; - if (e.value != null) { - System.out.println(pad + "Value: " + e.value); - } else if (e.name != null) { - System.out.println(pad + "Identifier: " + e.name); - } else if (e.left != null && e.right != null && e.op != null) { - // This might be a BinaryOpNode that got cast to ExprNode - System.out.println(pad + "BinaryOp: " + e.op); - print(e.left, indent + 1); - print(e.right, indent + 1); - } else if (e instanceof IndexAccessNode) { - // Handle IndexAccessNode that got cast to ExprNode - IndexAccessNode idx = (IndexAccessNode) e; - System.out.println(pad + "IndexAccess"); - System.out.print(pad + " Array: "); - print(idx.array, indent + 2); - System.out.print(pad + " Index: "); - print(idx.index, indent + 2); - } else { - System.out.println( - pad + "Expr (unresolved - name: " + e.name + ", value: " + e.value + ")"); - } - - } else if (node instanceof ParamNode) { - ParamNode p = (ParamNode) node; - System.out.println(pad + "Param: " + p.type + " " + p.name); - - } else if (node instanceof SlotNode) { - SlotNode s = (SlotNode) node; - System.out.println(pad + "Slot: " + s.name); - - } else if (node instanceof BlockNode) { - BlockNode block = (BlockNode) node; - System.out.println(pad + "Block:"); - for (StatementNode s : block.statements) print(s, indent + 1); - - } else if (node instanceof OutputNode) { - OutputNode p = (OutputNode) node; - System.out.print(pad + "Output"); - if (p.varName != null) System.out.print(" Var: " + p.varName); - System.out.println(); - - if (p.arguments.isEmpty()) { - System.out.println(pad + " (no arguments)"); - } else { - for (int i = 0; i < p.arguments.size(); i++) { - System.out.print(pad + " Argument " + i + ": "); - print(p.arguments.get(i), indent + 2); - } + println("UNARY: " + unary.op); + indent++; + visit(unary.operand); + indent--; + } else if (node.value != null) { + println("value: " + node.value); + } else if (node.name != null) { + println("IDENTIFIER: " + node.name); + } else if (node.left != null && node.right != null && node.op != null) { + // This might be a BinaryOpNode that got cast to ExprNode + println("| BINARY operation: " + node.op); + println("| left:"); + indent += 2; + visit(node.left); + indent -= 2; + println("| right:"); + indent += 2; + visit(node.right); + indent -= 2; + } else { + println("EXPR (unresolved - name: " + node.name + ", value: " + node.value + ")"); + } + return null; + } + + @Override + public Void visit(BinaryOpNode node) { + println("| BINARY operation: " + node.op); + println("| left:"); + indent += 2; + if (node.left != null) visit(node.left); + indent -= 2; + println("| right:"); + indent += 2; + if (node.right != null) visit(node.right); + indent -= 2; + return null; + } + + @Override + public Void visit(UnaryNode node) { + println("UNARY: " + node.op); + indent++; + if (node.operand != null) visit(node.operand); + indent--; + return null; + } + + @Override + public Void visit(TypeCastNode node) { + println("TYPECAST: " + node.targetType); + println("| expression:"); + indent += 2; + if (node.expression != null) visit(node.expression); + indent -= 2; + return null; + } + + @Override + public Void visit(MethodCallNode node) { + print("IDENTIFIER/CALL: " + (node.qualifiedName != null ? node.qualifiedName : node.name)); + if (node.slotNames != null && !node.slotNames.isEmpty()) { + System.out.print(" (slot_cast: "); + for (int i = 0; i < node.slotNames.size(); i++) { + if (i > 0) System.out.print(", "); + System.out.print(node.slotNames.get(i)); } - - } else if (node instanceof InputNode) { - InputNode input = (InputNode) node; - System.out.println( - pad + "Input: " + input.variableName + " = (" + input.targetType + ") input"); - - } else if (node instanceof VarNode) { - VarNode v = (VarNode) node; - System.out.print(pad + "Var: " + v.name); - if (v.value != null) { - System.out.println(" = "); - print(v.value, indent + 1); - } else { - System.out.println(); + System.out.print(")"); + } + if (node.chainType != null) { + System.out.print(" (chain: " + node.chainType + ")"); + } + System.out.println(); + + if (node.chainArguments != null && !node.chainArguments.isEmpty()) { + println("| CHAIN arguments:"); + indent += 2; + for (ExprNode arg : node.chainArguments) { + visit(arg); } - - } else if (node instanceof IfNode) { - IfNode ifn = (IfNode) node; - System.out.println(pad + "If"); - System.out.print(pad + " Condition: "); - print(ifn.condition, indent + 2); - System.out.println(pad + " Then:"); - print(ifn.thenBlock, indent + 2); - if (!ifn.elseBlock.statements.isEmpty()) { - System.out.println(pad + " Else:"); - print(ifn.elseBlock, indent + 2); + indent -= 2; + } + + if (node.arguments != null && !node.arguments.isEmpty()) { + println("| ARGUMENTS:"); + indent += 2; + for (ExprNode arg : node.arguments) { + visit(arg); } - - } else if (node instanceof RangeNode) { - RangeNode r = (RangeNode) node; - System.out.print(pad + "Range: step "); - print(r.step, 0); - System.out.print(" in "); - print(r.start, 0); - System.out.print(" to "); - print(r.end, 0); - System.out.println(); - - } else if (node instanceof ForNode) { - ForNode f = (ForNode) node; - System.out.println(pad + "For iterator: " + f.iterator); - System.out.print(pad + " Range: "); - print(f.range, 0); - System.out.println(); - System.out.println(pad + " Body:"); - print(f.body, indent + 2); - - } else if (node instanceof ReturnSlotAssignmentNode) { - ReturnSlotAssignmentNode rsa = (ReturnSlotAssignmentNode) node; - System.out.println(pad + "ReturnSlotAssignment:"); - System.out.println(pad + " Variables: " + rsa.variableNames); - System.out.print(pad + " MethodCall: "); - print(rsa.methodCall, indent + 2); - + indent -= 2; } else { - System.out.println(pad + node.getClass().getSimpleName()); + println("| (no arguments)"); } + return null; } - + + @Override + public Void visit(ArrayNode node) { + println("ARRAY literal with " + node.elements.size() + " elements:"); + indent++; + for (int i = 0; i < node.elements.size(); i++) { + println("[" + i + "]:"); + indent++; + visit(node.elements.get(i)); + indent--; + } + indent--; + return null; + } + + @Override + public Void visit(IndexAccessNode node) { + println("INDEX access"); + println("| ARRAY:"); + indent += 2; + if (node.array != null) visit(node.array); + indent -= 2; + println("| INDEX:"); + indent += 2; + if (node.index != null) visit(node.index); + indent -= 2; + return null; + } + + @Override + public Void visit(EqualityChainNode node) { + println("EQUALITY chain: " + (node.isAllChain ? ALL : ANY) + " " + node.operator); + println("| LEFT:"); + indent += 2; + if (node.left != null) visit(node.left); + indent -= 2; + println("| CHAIN arguments:"); + indent += 2; + for (ExprNode arg : node.chainArguments) { + visit(arg); + } + indent -= 2; + return null; + } + + @Override + public Void visit(BooleanChainNode node) { + println("BOOLEAN chain: " + (node.isAll ? ALL : ANY)); + indent++; + for (ExprNode expr : node.expressions) { + visit(expr); + } + indent--; + return null; + } + + @Override + public Void visit(SlotNode node) { + println("SLOT: " + node.name + " (type: " + node.type + ")"); + return null; + } + public static void print(ASTNode node) { - print(node, 0); + ASTPrinter printer = new ASTPrinter(); + printer.visit(node); } } \ No newline at end of file diff --git a/src/main/java/cod/ast/ASTVisitor.java b/src/main/java/cod/ast/ASTVisitor.java new file mode 100644 index 00000000..67085027 --- /dev/null +++ b/src/main/java/cod/ast/ASTVisitor.java @@ -0,0 +1,54 @@ +package cod.ast; + +import cod.ast.nodes.*; +import java.util.List; + +public interface ASTVisitor { + + // Program structure + T visit(ProgramNode node); + T visit(UnitNode node); + T visit(UseNode node); + + // Type declarations + T visit(TypeNode node); + T visit(FieldNode node); + T visit(MethodNode node); + T visit(ParamNode node); + T visit(ConstructorNode node); + + // Statements + T visit(BlockNode node); + T visit(AssignmentNode node); + T visit(VarNode node); + T visit(StmtIfNode node); + T visit(ExprIfNode node); + T visit(ForNode node); + T visit(RangeNode node); + T visit(OutputNode node); + T visit(InputNode node); + T visit(ExitNode node); + T visit(TupleNode node); + T visit(ReturnSlotAssignmentNode node); + T visit(SlotDeclarationNode node); + T visit(SlotAssignmentNode node); + T visit(MultipleSlotAssignmentNode node); + + // Expressions + T visit(ExprNode node); + T visit(BinaryOpNode node); + T visit(UnaryNode node); + T visit(TypeCastNode node); + T visit(MethodCallNode node); + T visit(ArrayNode node); + T visit(IndexAccessNode node); + T visit(EqualityChainNode node); + T visit(BooleanChainNode node); + T visit(SlotNode node); + + T visit(ASTNode node); + + // Utility methods for visiting lists + List visitList(List nodes); + void visitAll(List nodes); +} \ No newline at end of file diff --git a/src/main/java/cod/ast/BaseASTVisitor.java b/src/main/java/cod/ast/BaseASTVisitor.java new file mode 100644 index 00000000..3eddc9c7 --- /dev/null +++ b/src/main/java/cod/ast/BaseASTVisitor.java @@ -0,0 +1,205 @@ +package cod.ast; + +import cod.ast.nodes.*; +import java.util.ArrayList; +import java.util.List; + +public abstract class BaseASTVisitor implements ASTVisitor { + + protected T defaultVisit(ASTNode node) { + return null; + } + + @Override + public T visit(ProgramNode node) { + return node.accept(this); + } + + @Override + public T visit(UnitNode node) { + return node.accept(this); + } + + @Override + public T visit(UseNode node) { + return node.accept(this); + } + + @Override + public T visit(TypeNode node) { + return node.accept(this); + } + + @Override + public T visit(FieldNode node) { + return node.accept(this); + } + + @Override + public T visit(MethodNode node) { + return node.accept(this); + } + + @Override + public T visit(ParamNode node) { + return node.accept(this); + } + + @Override + public T visit(ConstructorNode node) { + return node.accept(this); + } + + @Override + public T visit(BlockNode node) { + return node.accept(this); + } + + @Override + public T visit(AssignmentNode node) { + return node.accept(this); + } + + @Override + public T visit(VarNode node) { + return node.accept(this); + } + + @Override + public T visit(StmtIfNode node) { + return node.accept(this); + } + + @Override + public T visit(ExprIfNode node) { + return node.accept(this); + } + + + @Override + public T visit(ForNode node) { + return node.accept(this); + } + + @Override + public T visit(RangeNode node) { + return node.accept(this); + } + + @Override + public T visit(OutputNode node) { + return node.accept(this); + } + + @Override + public T visit(InputNode node) { + return node.accept(this); + } + + @Override + public T visit(ExitNode node) { + return node.accept(this); + } + + @Override + public T visit(TupleNode node) { + return node.accept(this); + } + + @Override + public T visit(ReturnSlotAssignmentNode node) { + return node.accept(this); + } + + @Override + public T visit(SlotDeclarationNode node) { + return node.accept(this); + } + + @Override + public T visit(SlotAssignmentNode node) { + return node.accept(this); + } + + @Override + public T visit(MultipleSlotAssignmentNode node) { + return node.accept(this); + } + + @Override + public T visit(ExprNode node) { + return node.accept(this); + } + + @Override + public T visit(BinaryOpNode node) { + return node.accept(this); + } + + @Override + public T visit(UnaryNode node) { + return node.accept(this); + } + + @Override + public T visit(TypeCastNode node) { + return node.accept(this); + } + + @Override + public T visit(MethodCallNode node) { + return node.accept(this); + } + + @Override + public T visit(ArrayNode node) { + return node.accept(this); + } + + @Override + public T visit(IndexAccessNode node) { + return node.accept(this); + } + + @Override + public T visit(EqualityChainNode node) { + return node.accept(this); + } + + @Override + public T visit(BooleanChainNode node) { + return node.accept(this); + } + + @Override + public T visit(SlotNode node) { + return node.accept(this); + } + + @Override + public final T visit(ASTNode node) { + // This is the entry point - delegate to the node's accept method + return node.accept(this); + } + + @Override + public List visitList(List nodes) { + List results = new ArrayList(); + for (ASTNode node : nodes) { + results.add(visit(node)); + } + return results; + } + + @Override + public void visitAll(List nodes) { + for (ASTNode node : nodes) { + visit(node); + } + } + + // Helper method to dispatch via accept() - this is what should be used in InterpreterVisitor + public T dispatch(ASTNode node) { + return node.accept(this); + } +} diff --git a/src/main/java/cod/ast/ConstantFolder.java b/src/main/java/cod/ast/ConstantFolder.java new file mode 100644 index 00000000..fc9ba3a1 --- /dev/null +++ b/src/main/java/cod/ast/ConstantFolder.java @@ -0,0 +1,720 @@ +package cod.ast; + +import cod.ast.nodes.*; +import java.util.ArrayList; +import java.util.List; + +/** + * Constant Folding Visitor - Optimizes expressions by evaluating constant subexpressions at compile time. + * Implements ASTVisitor to transform the AST. + * + * UPDATED: Can work with flattened expressions for better optimization. + */ +public class ConstantFolder extends BaseASTVisitor { + + private final boolean useFlattening; + + public ConstantFolder() { + this(false); + } + + public ConstantFolder(boolean useFlattening) { + this.useFlattening = useFlattening; + } + + @Override + public ASTNode visit(BinaryOpNode node) { + // First, recursively fold children + ExprNode left = (ExprNode) dispatch(node.left); + ExprNode right = (ExprNode) dispatch(node.right); + + // Apply flattening if enabled + BinaryOpNode toEvaluate; + if (useFlattening && isAssociativeOperation(node.op)) { + // Try to flatten and collect constants + List operands = new ArrayList<>(); + List constantValues = new ArrayList<>(); + List variableOperands = new ArrayList<>(); + + collectAndSeparateOperands(left, node.op, operands, constantValues, variableOperands); + collectAndSeparateOperands(right, node.op, operands, constantValues, variableOperands); + + // If we have multiple constants, combine them + if (constantValues.size() > 1) { + Object combined = combineConstants(constantValues, node.op); + if (combined != null) { + // Replace multiple constants with one combined constant + constantValues.clear(); + constantValues.add(combined); + } + } + + // Rebuild expression with combined constants + if (constantValues.size() == 1 && variableOperands.isEmpty()) { + // All operands were constants + return createConstantNode(constantValues.get(0)); + } else if (constantValues.size() == 1 && variableOperands.size() == 1) { + // One constant, one variable - create simple binary op + toEvaluate = new BinaryOpNode(); + toEvaluate.left = variableOperands.get(0); + toEvaluate.op = node.op; + toEvaluate.right = createConstantNode(constantValues.get(0)); + } else { + // Rebuild flattened structure + return rebuildFlattenedExpression(variableOperands, constantValues, node.op); + } + } else { + toEvaluate = new BinaryOpNode(); + toEvaluate.left = left; + toEvaluate.op = node.op; + toEvaluate.right = right; + } + + // If both are constant literals, try to evaluate + if (isConstantLiteral(toEvaluate.left) && isConstantLiteral(toEvaluate.right)) { + Object leftVal = toEvaluate.left.value; + Object rightVal = toEvaluate.right.value; + String op = toEvaluate.op; + + try { + Object result = evaluateBinaryOp(leftVal, rightVal, op, toEvaluate); + if (result != null) { + stats.incrementConstantExpressions(); + return createConstantNode(result); + } + } catch (ArithmeticException e) { + // Division by zero, overflow, etc. - keep original expression + // The runtime will catch it + } + } + + // Return new node with folded children + return toEvaluate; + } + + // Helper method for flattening-aware constant collection + private void collectAndSeparateOperands(ExprNode expr, String targetOp, + List allOperands, + List constants, + List variables) { + if (expr instanceof BinaryOpNode) { + BinaryOpNode binExpr = (BinaryOpNode) expr; + if (binExpr.op.equals(targetOp)) { + // This is the same operation, recurse + collectAndSeparateOperands(binExpr.left, targetOp, allOperands, constants, variables); + collectAndSeparateOperands(binExpr.right, targetOp, allOperands, constants, variables); + return; + } + } + + // Not a matching binary op, add as operand + allOperands.add(expr); + if (isConstantLiteral(expr)) { + constants.add(expr.value); + } else { + variables.add(expr); + } + } + + private Object combineConstants(List constants, String op) { + if (constants.isEmpty()) return null; + + Object result = constants.get(0); + for (int i = 1; i < constants.size(); i++) { + result = evaluateBinaryOp(result, constants.get(i), op, null); + if (result == null) { + return null; // Can't combine these constants + } + } + return result; + } + + private ExprNode rebuildFlattenedExpression(List variables, + List constants, + String op) { + List allOperands = new ArrayList<>(); + allOperands.addAll(variables); + for (Object constant : constants) { + allOperands.add(createConstantNode(constant)); + } + + // Rebuild as right-associative chain + return buildBalancedTree(allOperands, 0, allOperands.size() - 1, op); + } + + private ExprNode buildBalancedTree(List operands, int start, int end, String op) { + if (start == end) { + return operands.get(start); + } + if (start + 1 == end) { + BinaryOpNode node = new BinaryOpNode(); + node.left = operands.get(start); + node.op = op; + node.right = operands.get(end); + return node; + } + + int mid = (start + end) / 2; + BinaryOpNode node = new BinaryOpNode(); + node.left = buildBalancedTree(operands, start, mid, op); + node.op = op; + node.right = buildBalancedTree(operands, mid + 1, end, op); + return node; + } + + private boolean isAssociativeOperation(String op) { + return op.equals("+") || op.equals("*"); + } + + // ... [REST OF THE ORIGINAL ConstantFolder CODE REMAINS THE SAME] ... + // The visit methods for other node types remain unchanged from your original + + @Override + public ASTNode visit(BooleanChainNode node) { + BooleanChainNode folded = new BooleanChainNode(); + folded.isAll = node.isAll; + folded.expressions = new ArrayList<>(); + + boolean allConstants = true; + List constantValues = new ArrayList<>(); + + // First, fold all expressions + for (ExprNode expr : node.expressions) { + ExprNode foldedExpr = (ExprNode) dispatch(expr); + folded.expressions.add(foldedExpr); + + if (isConstantLiteral(foldedExpr)) { + constantValues.add(foldedExpr.value); + } else { + allConstants = false; + } + } + + // If all expressions are constants, evaluate the boolean chain + if (allConstants && !constantValues.isEmpty()) { + boolean result; + + if (node.isAll) { + // all[]: All must be true + result = true; + for (Object val : constantValues) { + if (val instanceof Boolean) { + if (!(Boolean) val) { + result = false; + break; + } + } else { + // Non-boolean in boolean chain - can't fold + return folded; + } + } + } else { + // any[]: At least one must be true + result = false; + for (Object val : constantValues) { + if (val instanceof Boolean) { + if ((Boolean) val) { + result = true; + break; + } + } else { + // Non-boolean in boolean chain - can't fold + return folded; + } + } + } + + // Create a boolean constant with the result + stats.incrementBooleanChains(); + return createConstantNode(result); + } + + return folded; + } + + @Override + public ASTNode visit(EqualityChainNode node) { + EqualityChainNode folded = new EqualityChainNode(); + folded.left = (ExprNode) dispatch(node.left); + folded.operator = node.operator; + folded.isAllChain = node.isAllChain; + folded.chainArguments = new ArrayList<>(); + + // Check if left side is constant + boolean leftConstant = isConstantLiteral(folded.left); + List rightConstants = new ArrayList<>(); + boolean allRightConstants = true; + + // Fold all chain arguments + for (ExprNode arg : node.chainArguments) { + ExprNode foldedArg = (ExprNode) dispatch(arg); + folded.chainArguments.add(foldedArg); + + if (isConstantLiteral(foldedArg)) { + rightConstants.add(foldedArg.value); + } else { + allRightConstants = false; + } + } + + // If both left and all right arguments are constants, evaluate the chain + if (leftConstant && allRightConstants && !rightConstants.isEmpty()) { + Object leftVal = folded.left.value; + boolean result; + + if (node.isAllChain) { + // all[] chain: All comparisons must be true + result = true; + for (Object rightVal : rightConstants) { + boolean comparison = evaluateComparison(leftVal, rightVal, node.operator); + if (!comparison) { + result = false; + break; + } + } + } else { + // any[] chain: At least one comparison must be true + result = false; + for (Object rightVal : rightConstants) { + boolean comparison = evaluateComparison(leftVal, rightVal, node.operator); + if (comparison) { + result = true; + break; + } + } + } + + // Create a boolean constant with the result + stats.incrementConstantExpressions(); + return createConstantNode(result); + } + + return folded; + } + + @Override + public ASTNode visit(UnaryNode node) { + ExprNode operand = (ExprNode) dispatch(node.operand); + + if (isConstantLiteral(operand)) { + Object val = operand.value; + String op = node.op; + + Object result = evaluateUnaryOp(val, op, node); + if (result != null) { + stats.incrementConstantExpressions(); + return createConstantNode(result); + } + } + + UnaryNode folded = new UnaryNode(); + folded.op = node.op; + folded.operand = operand; + return folded; + } + + @Override + public ASTNode visit(TypeCastNode node) { + ExprNode expr = (ExprNode) dispatch(node.expression); + + if (isConstantLiteral(expr)) { + Object val = expr.value; + String targetType = node.targetType; + + try { + Object result = evaluateTypeCast(val, targetType, node); + if (result != null) { + stats.incrementTypeCasts(); + return createConstantNode(result); + } + } catch (ClassCastException | NumberFormatException e) { + // Invalid cast - keep original + } + } + + TypeCastNode folded = new TypeCastNode(); + folded.targetType = node.targetType; + folded.expression = expr; + return folded; + } + + @Override + public ASTNode visit(ExprNode node) { + // For literals, just return a copy + if (node.value != null || node.isNull) { + ExprNode copy = new ExprNode(); + copy.value = node.value; + copy.isNull = node.isNull; + copy.name = node.name; + return copy; + } + + // For identifiers, cannot fold + ExprNode copy = new ExprNode(); + copy.name = node.name; + return copy; + } + + @Override + public ASTNode visit(ArrayNode node) { + ArrayNode folded = new ArrayNode(); + folded.elements = new ArrayList<>(); + + for (ExprNode elem : node.elements) { + folded.elements.add((ExprNode) dispatch(elem)); + } + return folded; + } + + @Override + public ASTNode visit(TupleNode node) { + TupleNode folded = new TupleNode(); + folded.elements = new ArrayList<>(); + + for (ExprNode elem : node.elements) { + folded.elements.add((ExprNode) dispatch(elem)); + } + return folded; + } + + @Override + public ASTNode visit(MethodCallNode node) { + // Method calls are not constant-foldable (unless they're pure builtins, + // but that's a more advanced optimization) + MethodCallNode folded = new MethodCallNode(); + folded.name = node.name; + folded.qualifiedName = node.qualifiedName; + folded.slotNames = new ArrayList<>(node.slotNames); + folded.chainType = node.chainType; + folded.arguments = new ArrayList<>(); + + for (ExprNode arg : node.arguments) { + folded.arguments.add((ExprNode) dispatch(arg)); + } + + if (node.chainArguments != null) { + folded.chainArguments = new ArrayList<>(); + for (ExprNode arg : node.chainArguments) { + folded.chainArguments.add((ExprNode) dispatch(arg)); + } + } + + return folded; + } + + @Override + public ASTNode visit(IndexAccessNode node) { + IndexAccessNode folded = new IndexAccessNode(); + folded.array = (ExprNode) dispatch(node.array); + folded.index = (ExprNode) dispatch(node.index); + return folded; + } + + // Helper methods for evaluation + + private boolean evaluateComparison(Object left, Object right, String operator) { + if (left == null || right == null) { + switch (operator) { + case "==": return left == right; + case "!=": return left != right; + default: return false; + } + } + + if (left instanceof Number && right instanceof Number) { + double l = ((Number) left).doubleValue(); + double r = ((Number) right).doubleValue(); + + switch (operator) { + case "==": return Math.abs(l - r) < 1e-12; + case "!=": return Math.abs(l - r) >= 1e-12; + case "<": return l < r; + case ">": return l > r; + case "<=": return l <= r; + case ">=": return l >= r; + default: return false; + } + } + + if (left instanceof Boolean && right instanceof Boolean) { + boolean l = (Boolean) left; + boolean r = (Boolean) right; + + switch (operator) { + case "==": return l == r; + case "!=": return l != r; + default: return false; + } + } + + if (left instanceof String && right instanceof String) { + String l = (String) left; + String r = (String) right; + + switch (operator) { + case "==": return l.equals(r); + case "!=": return !l.equals(r); + default: return false; + } + } + + return false; + } + + private Object evaluateBinaryOp(Object left, Object right, String op, BinaryOpNode node) { + // Handle numeric operations + if (left instanceof Number && right instanceof Number) { + double l = ((Number) left).doubleValue(); + double r = ((Number) right).doubleValue(); + + switch (op) { + case "+": return l + r; + case "-": return l - r; + case "*": return l * r; + case "/": + if (r == 0) throw new ArithmeticException("Division by zero"); + return l / r; + case "%": return l % r; + case "<": return l < r; + case ">": return l > r; + case "<=": return l <= r; + case ">=": return l >= r; + case "==": return Math.abs(l - r) < 1e-12; + case "!=": return Math.abs(l - r) >= 1e-12; + default: return null; + } + } + + // Handle boolean operations (only equality for booleans in your language) + if (left instanceof Boolean && right instanceof Boolean) { + boolean l = (Boolean) left; + boolean r = (Boolean) right; + + switch (op) { + case "==": return l == r; + case "!=": return l != r; + default: return null; + } + } + + // Handle string concatenation + if (op.equals("+") && (left instanceof String || right instanceof String)) { + return left.toString() + right.toString(); + } + + // Handle equality for null + if (left == null || right == null) { + switch (op) { + case "==": return left == right; + case "!=": return left != right; + default: return null; + } + } + + return null; + } + + private Object evaluateUnaryOp(Object val, String op, UnaryNode node) { + if (val instanceof Number) { + double num = ((Number) val).doubleValue(); + switch (op) { + case "+": return +num; + case "-": return -num; + default: return null; + } + } + + if (val instanceof Boolean && op.equals("!")) { + return !(Boolean) val; + } + + return null; + } + + private Object evaluateTypeCast(Object val, String targetType, TypeCastNode node) { + if (val == null) return null; + + targetType = targetType.toLowerCase(); + + try { + switch (targetType) { + case "int": + if (val instanceof Number) return ((Number) val).intValue(); + if (val instanceof String) return Integer.parseInt((String) val); + break; + + case "float": + if (val instanceof Number) return ((Number) val).floatValue(); + if (val instanceof String) return Float.parseFloat((String) val); + break; + + case "text": + return val.toString(); + + case "bool": + if (val instanceof Boolean) return val; + if (val instanceof Number) return ((Number) val).doubleValue() != 0; + if (val instanceof String) return Boolean.parseBoolean((String) val); + break; + } + } catch (NumberFormatException e) { + // Invalid cast, keep original + } + + return null; + } + + private boolean isConstantLiteral(ExprNode node) { + return node != null && (node.value != null || node.isNull); + } + + private ExprNode createConstantNode(Object value) { + ExprNode node = new ExprNode(); + + if (value == null) { + node.isNull = true; + } else if (value instanceof Integer) { + node.value = value; + } else if (value instanceof Float) { + node.value = value; + } else if (value instanceof Double) { + node.value = ((Double) value).floatValue(); + } else if (value instanceof Boolean) { + node.value = value; + } else if (value instanceof String) { + node.value = value; + } + + return node; + } + + // Pass-through methods for statements + + @Override + public ASTNode visit(AssignmentNode node) { + AssignmentNode folded = new AssignmentNode(); + folded.left = (ExprNode) dispatch(node.left); + folded.right = (ExprNode) dispatch(node.right); + return folded; + } + + @Override + public ASTNode visit(VarNode node) { + VarNode folded = new VarNode(); + folded.name = node.name; + folded.explicitType = node.explicitType; + if (node.value != null) { + folded.value = (ExprNode) dispatch(node.value); + } + return folded; + } + + @Override + public ASTNode visit(StmtIfNode node) { + StmtIfNode folded = new StmtIfNode(); + folded.condition = (ExprNode) dispatch(node.condition); + folded.thenBlock = (BlockNode) dispatch(node.thenBlock); + folded.elseBlock = (BlockNode) dispatch(node.elseBlock); + return folded; + } + + @Override + public ASTNode visit(ForNode node) { + ForNode folded = new ForNode(); + folded.iterator = node.iterator; + folded.range = (RangeNode) dispatch(node.range); + folded.body = (BlockNode) dispatch(node.body); + return folded; + } + + @Override + public ASTNode visit(RangeNode node) { + RangeNode folded = new RangeNode(); + if (node.step != null) { + folded.step = (ExprNode) dispatch(node.step); + } + folded.start = (ExprNode) dispatch(node.start); + folded.end = (ExprNode) dispatch(node.end); + return folded; + } + + @Override + public ASTNode visit(OutputNode node) { + OutputNode folded = new OutputNode(); + folded.varName = node.varName; + folded.arguments = new ArrayList<>(); + for (ExprNode arg : node.arguments) { + folded.arguments.add((ExprNode) dispatch(arg)); + } + return folded; + } + + @Override + public ASTNode visit(BlockNode node) { + BlockNode folded = new BlockNode(); + folded.statements = new ArrayList<>(); + for (StmtNode stmt : node.statements) { + folded.statements.add((StmtNode) dispatch(stmt)); + } + return folded; + } + + @Override + public ASTNode visit(SlotAssignmentNode node) { + SlotAssignmentNode folded = new SlotAssignmentNode(); + folded.slotName = node.slotName; + folded.value = (ExprNode) dispatch(node.value); + return folded; + } + + @Override + public ASTNode visit(MultipleSlotAssignmentNode node) { + MultipleSlotAssignmentNode folded = new MultipleSlotAssignmentNode(); + folded.assignments = new ArrayList<>(); + for (SlotAssignmentNode assign : node.assignments) { + folded.assignments.add((SlotAssignmentNode) dispatch(assign)); + } + return folded; + } + + @Override + public ASTNode visit(ReturnSlotAssignmentNode node) { + ReturnSlotAssignmentNode folded = new ReturnSlotAssignmentNode(); + folded.variableNames = new ArrayList<>(node.variableNames); + folded.methodCall = (MethodCallNode) dispatch(node.methodCall); + return folded; + } + + // Default pass-through for other node types + @Override + public ASTNode visit(ProgramNode node) { return node; } + @Override + public ASTNode visit(UnitNode node) { return node; } + @Override + public ASTNode visit(UseNode node) { return node; } + @Override + public ASTNode visit(TypeNode node) { return node; } + @Override + public ASTNode visit(FieldNode node) { return node; } + @Override + public ASTNode visit(MethodNode node) { return node; } + @Override + public ASTNode visit(ParamNode node) { return node; } + @Override + public ASTNode visit(ConstructorNode node) { return node; } + @Override + public ASTNode visit(InputNode node) { return node; } + @Override + public ASTNode visit(ExitNode node) { return node; } + @Override + public ASTNode visit(SlotDeclarationNode node) { return node; } + @Override + public ASTNode visit(SlotNode node) { return node; } + + // Statistics tracking + private static OptimizationStats stats = new OptimizationStats(); + + public static OptimizationStats getStats() { + return stats; + } +} \ No newline at end of file diff --git a/src/main/java/cod/ast/ExpressionFlattener.java b/src/main/java/cod/ast/ExpressionFlattener.java new file mode 100644 index 00000000..c9c64cda --- /dev/null +++ b/src/main/java/cod/ast/ExpressionFlattener.java @@ -0,0 +1,341 @@ +package cod.ast; + +import cod.ast.nodes.*; +import java.util.*; + +/** + * Flattens nested expressions to prepare for TAC generation. + * Transforms deeply nested binary operations into shallower, + * more linear forms for better optimization and code generation. + */ +public class ExpressionFlattener extends BaseASTVisitor { + + /** + * Main entry point for flattening an entire AST + */ + public ASTNode flatten(ASTNode node) { + return visit(node); + } + + // === EXPRESSION FLATTENING === + + @Override + public ASTNode visit(BinaryOpNode node) { + // First flatten children + ExprNode left = (ExprNode) dispatch(node.left); + ExprNode right = (ExprNode) dispatch(node.right); + + // Check if this is an associative operation we can flatten + if (isAssociativeOperation(node.op)) { + // Collect all operands at this precedence level + List operands = new ArrayList<>(); + collectOperands(left, node.op, operands); + collectOperands(right, node.op, operands); + + // If we have more than 2 operands, create a flattened structure + if (operands.size() > 2) { + return createFlattenedBinaryChain(operands, node.op); + } + } + + // Return regular binary node with flattened children + BinaryOpNode result = new BinaryOpNode(); + result.left = left; + result.op = node.op; + result.right = right; + return result; + } + + @Override + public ASTNode visit(UnaryNode node) { + ExprNode operand = (ExprNode) dispatch(node.operand); + + // Handle double negatives: !!x → x, -(-x) → x + if (node.op.equals("!") && operand instanceof UnaryNode) { + UnaryNode inner = (UnaryNode) operand; + if (inner.op.equals("!")) { + return inner.operand; // Remove double negation + } + } else if (node.op.equals("-") && operand instanceof UnaryNode) { + UnaryNode inner = (UnaryNode) operand; + if (inner.op.equals("-")) { + return inner.operand; // Remove double negative + } + } + + UnaryNode result = new UnaryNode(); + result.op = node.op; + result.operand = operand; + return result; + } + + @Override + public ASTNode visit(EqualityChainNode node) { + EqualityChainNode flattened = new EqualityChainNode(); + flattened.left = (ExprNode) dispatch(node.left); + flattened.operator = node.operator; + flattened.isAllChain = node.isAllChain; + flattened.chainArguments = new ArrayList<>(); + + for (ExprNode arg : node.chainArguments) { + flattened.chainArguments.add((ExprNode) dispatch(arg)); + } + return flattened; + } + + @Override + public ASTNode visit(BooleanChainNode node) { + BooleanChainNode flattened = new BooleanChainNode(); + flattened.isAll = node.isAll; + flattened.expressions = new ArrayList<>(); + + for (ExprNode expr : node.expressions) { + flattened.expressions.add((ExprNode) dispatch(expr)); + } + return flattened; + } + + @Override + public ASTNode visit(TypeCastNode node) { + TypeCastNode flattened = new TypeCastNode(); + flattened.targetType = node.targetType; + flattened.expression = (ExprNode) dispatch(node.expression); + return flattened; + } + + @Override + public ASTNode visit(MethodCallNode node) { + MethodCallNode flattened = new MethodCallNode(); + flattened.name = node.name; + flattened.qualifiedName = node.qualifiedName; + flattened.slotNames = new ArrayList<>(node.slotNames); + flattened.chainType = node.chainType; + flattened.arguments = new ArrayList<>(); + + for (ExprNode arg : node.arguments) { + flattened.arguments.add((ExprNode) dispatch(arg)); + } + + if (node.chainArguments != null) { + flattened.chainArguments = new ArrayList<>(); + for (ExprNode arg : node.chainArguments) { + flattened.chainArguments.add((ExprNode) dispatch(arg)); + } + } + + return flattened; + } + + @Override + public ASTNode visit(ArrayNode node) { + ArrayNode flattened = new ArrayNode(); + flattened.elements = new ArrayList<>(); + + for (ExprNode elem : node.elements) { + flattened.elements.add((ExprNode) dispatch(elem)); + } + return flattened; + } + + @Override + public ASTNode visit(TupleNode node) { + TupleNode flattened = new TupleNode(); + flattened.elements = new ArrayList<>(); + + for (ExprNode elem : node.elements) { + flattened.elements.add((ExprNode) dispatch(elem)); + } + return flattened; + } + + @Override + public ASTNode visit(IndexAccessNode node) { + IndexAccessNode flattened = new IndexAccessNode(); + flattened.array = (ExprNode) dispatch(node.array); + flattened.index = (ExprNode) dispatch(node.index); + return flattened; + } + + @Override + public ASTNode visit(ExprNode node) { + // For literals and identifiers, just return a copy + if (node.value != null || node.isNull || node.name != null) { + ExprNode copy = new ExprNode(); + copy.value = node.value; + copy.isNull = node.isNull; + copy.name = node.name; + return copy; + } + return node; + } + + // === HELPER METHODS === + + private boolean isAssociativeOperation(String op) { + return op.equals("+") || op.equals("*") || + op.equals("&") || op.equals("|") || // For bitwise if supported + op.equals("&&") || op.equals("||"); // For logical operations + } + + private void collectOperands(ExprNode expr, String targetOp, List operands) { + if (expr instanceof BinaryOpNode) { + BinaryOpNode binExpr = (BinaryOpNode) expr; + if (binExpr.op.equals(targetOp)) { + // This is the same operation, recurse + collectOperands(binExpr.left, targetOp, operands); + collectOperands(binExpr.right, targetOp, operands); + return; + } + } + // Not a matching binary op, add as operand + operands.add(expr); + } + + private ExprNode createFlattenedBinaryChain(List operands, String op) { + // Rebuild as right-associative chain for consistent evaluation + // This creates a balanced tree: (a + b + c + d) → ((a + b) + (c + d)) + return buildBalancedTree(operands, 0, operands.size() - 1, op); + } + + private ExprNode buildBalancedTree(List operands, int start, int end, String op) { + if (start == end) { + return operands.get(start); + } + if (start + 1 == end) { + BinaryOpNode node = new BinaryOpNode(); + node.left = operands.get(start); + node.op = op; + node.right = operands.get(end); + return node; + } + + int mid = (start + end) / 2; + BinaryOpNode node = new BinaryOpNode(); + node.left = buildBalancedTree(operands, start, mid, op); + node.op = op; + node.right = buildBalancedTree(operands, mid + 1, end, op); + return node; + } + + // === PASS-THROUGH METHODS (statements and declarations) === + + @Override + public ASTNode visit(AssignmentNode node) { + AssignmentNode flattened = new AssignmentNode(); + flattened.left = (ExprNode) dispatch(node.left); + flattened.right = (ExprNode) dispatch(node.right); + return flattened; + } + + @Override + public ASTNode visit(VarNode node) { + VarNode flattened = new VarNode(); + flattened.name = node.name; + flattened.explicitType = node.explicitType; + if (node.value != null) { + flattened.value = (ExprNode) dispatch(node.value); + } + return flattened; + } + + @Override + public ASTNode visit(StmtIfNode node) { + StmtIfNode flattened = new StmtIfNode(); + flattened.condition = (ExprNode) dispatch(node.condition); + flattened.thenBlock = (BlockNode) dispatch(node.thenBlock); + flattened.elseBlock = (BlockNode) dispatch(node.elseBlock); + return flattened; + } + + @Override + public ASTNode visit(ForNode node) { + ForNode flattened = new ForNode(); + flattened.iterator = node.iterator; + flattened.range = (RangeNode) dispatch(node.range); + flattened.body = (BlockNode) dispatch(node.body); + return flattened; + } + + @Override + public ASTNode visit(RangeNode node) { + RangeNode flattened = new RangeNode(); + if (node.step != null) { + flattened.step = (ExprNode) dispatch(node.step); + } + flattened.start = (ExprNode) dispatch(node.start); + flattened.end = (ExprNode) dispatch(node.end); + return flattened; + } + + @Override + public ASTNode visit(OutputNode node) { + OutputNode flattened = new OutputNode(); + flattened.varName = node.varName; + flattened.arguments = new ArrayList<>(); + for (ExprNode arg : node.arguments) { + flattened.arguments.add((ExprNode) dispatch(arg)); + } + return flattened; + } + + @Override + public ASTNode visit(BlockNode node) { + BlockNode flattened = new BlockNode(); + flattened.statements = new ArrayList<>(); + for (StmtNode stmt : node.statements) { + flattened.statements.add((StmtNode) dispatch(stmt)); + } + return flattened; + } + + // Default pass-through for other node types + @Override + public ASTNode visit(ProgramNode node) { return node; } + @Override + public ASTNode visit(UnitNode node) { return node; } + @Override + public ASTNode visit(UseNode node) { return node; } + @Override + public ASTNode visit(TypeNode node) { return node; } + @Override + public ASTNode visit(FieldNode node) { return node; } + @Override + public ASTNode visit(MethodNode node) { return node; } + @Override + public ASTNode visit(ParamNode node) { return node; } + @Override + public ASTNode visit(ConstructorNode node) { return node; } + @Override + public ASTNode visit(InputNode node) { return node; } + @Override + public ASTNode visit(ExitNode node) { return node; } + @Override + public ASTNode visit(SlotDeclarationNode node) { return node; } + @Override + public ASTNode visit(SlotNode node) { return node; } + @Override + public ASTNode visit(SlotAssignmentNode node) { + SlotAssignmentNode flattened = new SlotAssignmentNode(); + flattened.slotName = node.slotName; + flattened.value = (ExprNode) dispatch(node.value); + return flattened; + } + + @Override + public ASTNode visit(MultipleSlotAssignmentNode node) { + MultipleSlotAssignmentNode flattened = new MultipleSlotAssignmentNode(); + flattened.assignments = new ArrayList<>(); + for (SlotAssignmentNode assign : node.assignments) { + flattened.assignments.add((SlotAssignmentNode) dispatch(assign)); + } + return flattened; + } + + @Override + public ASTNode visit(ReturnSlotAssignmentNode node) { + ReturnSlotAssignmentNode flattened = new ReturnSlotAssignmentNode(); + flattened.variableNames = new ArrayList<>(node.variableNames); + flattened.methodCall = (MethodCallNode) dispatch(node.methodCall); + return flattened; + } +} \ No newline at end of file diff --git a/src/main/java/cod/ast/OptimizationStats.java b/src/main/java/cod/ast/OptimizationStats.java new file mode 100644 index 00000000..a64937be --- /dev/null +++ b/src/main/java/cod/ast/OptimizationStats.java @@ -0,0 +1,54 @@ +package cod.ast; + +/** + * Tracks statistics about optimization passes + */ +public class OptimizationStats { + private int constantExpressionsFolded = 0; + private int binaryOpsSimplified = 0; + private int booleanChainsOptimized = 0; + private int typeCastsEliminated = 0; + private long startTime = 0; + private long endTime = 0; + + public void startTiming() { + startTime = System.nanoTime(); + } + + public void stopTiming() { + endTime = System.nanoTime(); + } + + public void incrementConstantExpressions() { + constantExpressionsFolded++; + } + + public void incrementBinaryOps() { + binaryOpsSimplified++; + } + + public void incrementBooleanChains() { + booleanChainsOptimized++; + } + + public void incrementTypeCasts() { + typeCastsEliminated++; + } + + public void printSummary() { + long duration = endTime - startTime; + System.out.println("\n=== OPTIMIZATION SUMMARY ==="); + System.out.println("Constant expressions folded: " + constantExpressionsFolded); + System.out.println("Binary operations simplified: " + binaryOpsSimplified); + System.out.println("Boolean chains optimized: " + booleanChainsOptimized); + System.out.println("Type casts eliminated: " + typeCastsEliminated); + System.out.println("Total optimizations: " + getTotalOptimizations()); + System.out.printf("Optimization time: %.3f ms\n", duration / 1_000_000.0); + System.out.println("=============================\n"); + } + + public int getTotalOptimizations() { + return constantExpressionsFolded + binaryOpsSimplified + + booleanChainsOptimized + typeCastsEliminated; + } +} \ No newline at end of file diff --git a/src/main/java/cod/ast/Optimizer.java b/src/main/java/cod/ast/Optimizer.java new file mode 100644 index 00000000..3ce72271 --- /dev/null +++ b/src/main/java/cod/ast/Optimizer.java @@ -0,0 +1,88 @@ +package cod.ast; + +import cod.ast.nodes.*; + +public class Optimizer { + + private static OptimizationStats stats = new OptimizationStats(); + + /** + * Apply expression flattening optimization + */ + public static ASTNode flattenExpressions(ASTNode node) { + ExpressionFlattener flattener = new ExpressionFlattener(); + return flattener.flatten(node); + } + + /** + * Apply constant folding optimization to any AST node + */ + public static ASTNode foldConstants(ASTNode node) { + stats.startTiming(); + ConstantFolder folder = new ConstantFolder(); + ASTNode result = folder.visit(node); + stats.stopTiming(); + return result; + } + + /** + * Apply multiple optimization passes with intelligent ordering + */ + public static ASTNode optimize(ASTNode node, boolean flattenExpressions, + boolean constantFolding, boolean otherOptimizations) { + ASTNode result = node; + + // 1. First flatten expressions (exposes more constant folding opportunities) + if (flattenExpressions) { + result = flattenExpressions(result); + } + + // 2. Then fold constants (works better on flattened expressions) + if (constantFolding) { + result = foldConstants(result); + } + + // 3. Other optimizations (could include more flattening/folding cycles) + if (otherOptimizations) { + // Optionally run another round of flattening after constant folding + // to clean up newly created expression structures + if (flattenExpressions) { + result = flattenExpressions(result); + } + + // Add other optimization passes here as needed + // result = new Inliner().visit(result); + // result = new DeadCodeEliminator().visit(result); + } + + return result; + } + + /** + * Convenience method: full optimization pipeline + */ + public static ASTNode optimizeFull(ASTNode node) { + return optimize(node, true, true, false); + } + + /** + * Get optimization statistics + */ + public static OptimizationStats getStats() { + return stats; + } + + /** + * Reset optimization statistics + */ + public static void resetStats() { + stats = new OptimizationStats(); + } + + /** + * Print optimization statistics + */ + public static void printStats() { + stats.printSummary(); + } +} \ No newline at end of file From adb3aa8ec843e1739bdbbdfeaf224fdcc744934d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:26:38 +0800 Subject: [PATCH 32/54] Add files via upload --- src/main/java/cod/compiler/BasicBlock.java | 31 + .../cod/compiler/GraphColoringAllocator.java | 113 ++ .../java/cod/compiler/InterferenceGraph.java | 82 ++ .../java/cod/compiler/LivenessAnalyzer.java | 127 +++ .../java/cod/compiler/MTOTNativeCompiler.java | 977 +++++++++--------- src/main/java/cod/compiler/MTOTRegistry.java | 122 +++ .../java/cod/compiler/RegisterManager.java | 89 ++ src/main/java/cod/compiler/TACCompiler.java | 697 +++++++++++++ .../java/cod/compiler/TACInstruction.java | 117 +++ src/main/java/cod/compiler/TACProgram.java | 39 + 10 files changed, 1890 insertions(+), 504 deletions(-) create mode 100644 src/main/java/cod/compiler/BasicBlock.java create mode 100644 src/main/java/cod/compiler/GraphColoringAllocator.java create mode 100644 src/main/java/cod/compiler/InterferenceGraph.java create mode 100644 src/main/java/cod/compiler/LivenessAnalyzer.java create mode 100644 src/main/java/cod/compiler/MTOTRegistry.java create mode 100644 src/main/java/cod/compiler/RegisterManager.java create mode 100644 src/main/java/cod/compiler/TACCompiler.java create mode 100644 src/main/java/cod/compiler/TACInstruction.java create mode 100644 src/main/java/cod/compiler/TACProgram.java diff --git a/src/main/java/cod/compiler/BasicBlock.java b/src/main/java/cod/compiler/BasicBlock.java new file mode 100644 index 00000000..5a3110f4 --- /dev/null +++ b/src/main/java/cod/compiler/BasicBlock.java @@ -0,0 +1,31 @@ +package cod.compiler; + +import java.util.*; + +public class BasicBlock { + public int id; + public List instructions = new ArrayList(); + + // Graph edges + public List predecessors = new ArrayList(); + public List successors = new ArrayList(); + + // Liveness Sets + public Set def = new HashSet(); + public Set use = new HashSet(); + public Set liveIn = new HashSet(); + public Set liveOut = new HashSet(); + + public BasicBlock(int id) { + this.id = id; + } + + public void addInstruction(TACInstruction instr) { + instructions.add(instr); + } + + @Override + public String toString() { + return "Block " + id; + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/GraphColoringAllocator.java b/src/main/java/cod/compiler/GraphColoringAllocator.java new file mode 100644 index 00000000..10b1ba6c --- /dev/null +++ b/src/main/java/cod/compiler/GraphColoringAllocator.java @@ -0,0 +1,113 @@ +package cod.compiler; + +import cod.debug.DebugSystem; +import java.util.*; + +public class GraphColoringAllocator { + private final MTOTRegistry.RegisterFile registerFile; + private final RegisterManager.RegisterSpiller spiller; + // NEW: Store a reference to the InterferenceGraph + private InterferenceGraph interferenceGraph; + + public GraphColoringAllocator(MTOTRegistry.RegisterFile registerFile, RegisterManager.RegisterSpiller spiller) { + this.registerFile = registerFile; + this.spiller = spiller; + // Initialize the graph so it exists when RegisterManager calls the setter + this.interferenceGraph = new InterferenceGraph(); + } + + // NEW METHOD: Allows RegisterManager to access the graph for ABI setup + public InterferenceGraph getInterferenceGraph() { + return interferenceGraph; + } + + public Map allocate(InterferenceGraph graph) { + // ASSIGN THE INPUT GRAPH TO THE MEMBER VARIABLE BEFORE PROCEEDING + this.interferenceGraph = graph; + + DebugSystem.info("ALLOC", "Coloring graph with " + graph.adjList.size() + " nodes"); + + Stack stack = new Stack(); + Set spilledNodes = new HashSet(); + + // Deep copy graph for manipulation + Map> workingGraph = new HashMap>(); + Map workingDegrees = new HashMap(); + + for (Map.Entry> entry : graph.adjList.entrySet()) { + workingGraph.put(entry.getKey(), new HashSet(entry.getValue())); + workingDegrees.put(entry.getKey(), graph.degrees.get(entry.getKey())); + } + + int K = registerFile.generalPurpose.size(); + + // SIMPLIFY + int numNodes = workingGraph.size(); + while (stack.size() + spilledNodes.size() < numNodes) { + String nodeToRemove = null; + + // Find trivially colorable node + for (Map.Entry entry : workingDegrees.entrySet()) { + if (entry.getValue() != -1 && entry.getValue() < K) { + nodeToRemove = entry.getKey(); + break; + } + } + + // Optimistic Spill + if (nodeToRemove == null) { + int maxDegree = -1; + for (Map.Entry entry : workingDegrees.entrySet()) { + if (entry.getValue() != -1 && entry.getValue() > maxDegree) { + maxDegree = entry.getValue(); + nodeToRemove = entry.getKey(); + } + } + } + + if (nodeToRemove == null) break; + + stack.push(nodeToRemove); + workingDegrees.put(nodeToRemove, -1); + + for (String neighbor : workingGraph.get(nodeToRemove)) { + if (workingDegrees.get(neighbor) != -1) { + workingDegrees.put(neighbor, workingDegrees.get(neighbor) - 1); + } + } + } + + // SELECT + Map assignments = new HashMap(); + + while (!stack.isEmpty()) { + String node = stack.pop(); + Set usedColors = new HashSet(); + + if (graph.adjList.containsKey(node)) { + for (String neighbor : graph.adjList.get(node)) { + if (assignments.containsKey(neighbor)) { + usedColors.add(assignments.get(neighbor)); + } + } + } + + String chosenColor = null; + for (String reg : registerFile.generalPurpose) { + if (!usedColors.contains(reg)) { + chosenColor = reg; + break; + } + } + + if (chosenColor != null) { + assignments.put(node, chosenColor); + } else { + spiller.forceSpill(node); + spilledNodes.add(node); + } + } + + return assignments; + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/InterferenceGraph.java b/src/main/java/cod/compiler/InterferenceGraph.java new file mode 100644 index 00000000..267bb391 --- /dev/null +++ b/src/main/java/cod/compiler/InterferenceGraph.java @@ -0,0 +1,82 @@ +package cod.compiler; + +import java.util.*; + +public class InterferenceGraph { + public final Map> adjList = new HashMap>(); + public final Map degrees = new HashMap(); + + // NOTE: This will be injected/called by MTOTNativeCompiler + // to provide the necessary register sets (x9-x17 for AArch64) + public Set callerSavedRegisters = Collections.emptySet(); + + public void addNode(String node) { + if (!adjList.containsKey(node)) { + adjList.put(node, new HashSet()); + degrees.put(node, 0); + } + } + + public void addEdge(String u, String v) { + if (u.equals(v)) return; + addNode(u); + addNode(v); + if (adjList.get(u).add(v)) { + degrees.put(u, degrees.get(u) + 1); + } + if (adjList.get(v).add(u)) { + degrees.put(v, degrees.get(v) + 1); + } + } + + public void buildFromCFG(List blocks) { + for (BasicBlock block : blocks) { + Set liveNow = new HashSet(block.liveOut); + + for (int i = block.instructions.size() - 1; i >= 0; i--) { + TACInstruction instr = block.instructions.get(i); + + String def = instr.getDef(); + List uses = instr.getUses(); + + if (def != null) { + addNode(def); + for (String liveVar : liveNow) { + addEdge(def, liveVar); + } + liveNow.remove(def); + } + + if (instr.opcode == TACInstruction.Opcode.CALL || + instr.opcode == TACInstruction.Opcode.CALL_SLOTS) { + + // CRITICAL FIX: Add interference between live variables + // and ALL caller-saved registers (register clobbering model) + addCallInterferences(liveNow); + } + + for (String use : uses) { + addNode(use); + liveNow.add(use); + } + } + } + } + + /** + * Models the fact that a function call clobbers all caller-saved registers. + * Any variable currently live (in liveNow) must interfere with all + * caller-saved registers to ensure it is allocated to a callee-saved + * register or spilled to the stack. + */ + private void addCallInterferences(Set liveNow) { + for (String liveVar : liveNow) { + for (String clobberReg : callerSavedRegisters) { + // Add the caller-saved register as a pseudo-node in the graph + addNode(clobberReg); + // Add an edge from the live variable to the clobbered register + addEdge(liveVar, clobberReg); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/LivenessAnalyzer.java b/src/main/java/cod/compiler/LivenessAnalyzer.java new file mode 100644 index 00000000..ac40e8a0 --- /dev/null +++ b/src/main/java/cod/compiler/LivenessAnalyzer.java @@ -0,0 +1,127 @@ +package cod.compiler; + +import cod.compiler.TACInstruction.Opcode; +import java.util.*; + +public class LivenessAnalyzer { + + public List buildCFG(List instructions) { + List blocks = new ArrayList(); + if (instructions.isEmpty()) return blocks; + + Map labelToBlock = new HashMap(); + BasicBlock currentBlock = new BasicBlock(0); + blocks.add(currentBlock); + + for (int i = 0; i < instructions.size(); i++) { + TACInstruction instr = instructions.get(i); + + if (instr.opcode == Opcode.LABEL) { + if (!currentBlock.instructions.isEmpty()) { + currentBlock = new BasicBlock(blocks.size()); + blocks.add(currentBlock); + } + labelToBlock.put((String)instr.operand1, currentBlock); + } + + currentBlock.addInstruction(instr); + + if (isBranchOrTerminator(instr)) { + if (i + 1 < instructions.size()) { + currentBlock = new BasicBlock(blocks.size()); + blocks.add(currentBlock); + } + } + } + + // Compute Local Liveness (Def/Use) + for (BasicBlock block : blocks) { + computeLocalLiveness(block); + } + + // Connect Edges + for (int i = 0; i < blocks.size(); i++) { + BasicBlock block = blocks.get(i); + if (block.instructions.isEmpty()) continue; + + TACInstruction last = block.instructions.get(block.instructions.size() - 1); + + if (last.opcode == Opcode.GOTO) { + String targetLabel = (String) last.operand1; + connect(block, labelToBlock.get(targetLabel)); + } + else if (last.opcode == Opcode.IF_GOTO) { + // Operand2 holds the label in our compiler's emission logic + String targetLabel = (String) last.operand2; + if (i + 1 < blocks.size()) connect(block, blocks.get(i + 1)); // Fallthrough + if (targetLabel != null) connect(block, labelToBlock.get(targetLabel)); // Branch + } + else if (last.opcode == Opcode.RET) { + // No successors + } + else { + if (i + 1 < blocks.size()) connect(block, blocks.get(i + 1)); + } + } + + return blocks; + } + + private void connect(BasicBlock from, BasicBlock to) { + if (from != null && to != null) { + from.successors.add(to); + to.predecessors.add(from); + } + } + + private boolean isBranchOrTerminator(TACInstruction instr) { + switch (instr.opcode) { + case GOTO: case IF_GOTO: case RET: return true; + default: return false; + } + } + + private void computeLocalLiveness(BasicBlock block) { + block.def.clear(); + block.use.clear(); + + for (TACInstruction instr : block.instructions) { + List uses = instr.getUses(); + String def = instr.getDef(); + + for (String u : uses) { + if (!block.def.contains(u)) { + block.use.add(u); + } + } + if (def != null) { + block.def.add(def); + } + } + } + + public void computeGlobalLiveness(List blocks) { + boolean changed = true; + while (changed) { + changed = false; + for (int i = blocks.size() - 1; i >= 0; i--) { + BasicBlock block = blocks.get(i); + + Set newLiveOut = new HashSet(); + for (BasicBlock succ : block.successors) { + newLiveOut.addAll(succ.liveIn); + } + + Set newLiveIn = new HashSet(newLiveOut); + newLiveIn.removeAll(block.def); + newLiveIn.addAll(block.use); + + if (!newLiveIn.equals(block.liveIn) || !newLiveOut.equals(block.liveOut)) { + block.liveIn = newLiveIn; + block.liveOut = newLiveOut; + changed = true; + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/MTOTNativeCompiler.java b/src/main/java/cod/compiler/MTOTNativeCompiler.java index 2283bd65..42975ad7 100644 --- a/src/main/java/cod/compiler/MTOTNativeCompiler.java +++ b/src/main/java/cod/compiler/MTOTNativeCompiler.java @@ -3,559 +3,528 @@ import static cod.compiler.MTOTRegistry.*; import static cod.compiler.MTOTRegistry.AArch64Registers.*; import static cod.compiler.MTOTRegistry.x86_64Registers.*; -import cod.compiler.BytecodeInstruction.Opcode; -import cod.compiler.natives.*; - -import cod.ast.nodes.*; +import cod.compiler.TACInstruction.Opcode; import cod.debug.DebugSystem; import java.util.*; -import java.lang.reflect.Field; public class MTOTNativeCompiler { - public final CPUProfile cpuProfile; - - public final String thisRegister; - private final Set calleeSavedSet; - private final Set abiCallerSavedSet; - - public final RegisterManager registerManager; - private final RegisterManager.RegisterAllocator registerAllocator; - private final RegisterManager.RegisterSpiller spiller; - public final OperandStack operandStack; - - public List assemblyCode = new ArrayList(); - public final List dataSection = new ArrayList(); - - private int dataLabelCounter = 0; - private String currentMethodName = ""; - public final List argumentRegisters; - - private int currentPc = 0; - private List currentMethodBytecode = null; - private int currentLoopDepth = 0; - - public final RuntimeCallHelper runtimeCallHelper; - public final OperationCompiler operationCompiler; - public final MemoryAccessCompiler memoryAccessCompiler; - public final ControlFlowCompiler controlFlowCompiler; - public final MethodCallCompiler methodCallCompiler; - - public MTOTNativeCompiler(CPUProfile cpuProfile) { - this.cpuProfile = cpuProfile; - - if (cpuProfile.architecture.equals("aarch64")) { - this.thisRegister = AArch64Registers.x19; - this.calleeSavedSet = new HashSet(Arrays.asList( - x19, x20, x21, x22, x23, x24, x25, x26, x27, x28 - )); - this.abiCallerSavedSet = new HashSet(Arrays.asList( - x0, x1, x2, x3, x4, x5, x6, x7, - x9, x10, x11, x12, x13, x14, x15, x16, x17 - )); - } else { - this.thisRegister = x86_64Registers.r15; - this.calleeSavedSet = new HashSet(Arrays.asList( - x86_64Registers.rbx, x86_64Registers.r12, x86_64Registers.r13, - x86_64Registers.r14, x86_64Registers.r15 - )); - this.abiCallerSavedSet = new HashSet(Arrays.asList( - x86_64Registers.rax, x86_64Registers.rcx, x86_64Registers.rdx, - x86_64Registers.rsi, x86_64Registers.rdi, x86_64Registers.r8, - x86_64Registers.r9, x86_64Registers.r10, x86_64Registers.r11 - )); - } - - this.registerManager = new RegisterManager(this); - this.registerAllocator = this.registerManager.getAllocator(); - this.spiller = this.registerManager.getSpiller(); - this.operandStack = new OperandStack(this); - this.argumentRegisters = cpuProfile.registerFile.argumentRegisters; - - this.runtimeCallHelper = new RuntimeCallHelper(this); - this.operationCompiler = new OperationCompiler(this); - this.memoryAccessCompiler = new MemoryAccessCompiler(this); - this.controlFlowCompiler = new ControlFlowCompiler(this); - this.methodCallCompiler = new MethodCallCompiler(this); - } - - public int getCurrentPc() { return currentPc; } - public List getCurrentMethodBytecode() { return currentMethodBytecode; } - public int getCurrentLoopDepth() { return currentLoopDepth; } + public final CPUProfile cpuProfile; + public final String thisRegister; + private final Set abiCallerSavedSet; + public final List argumentRegisters; - public String compileMethodFromBytecode(String methodName, List bytecode) { - DebugSystem.debug("MTOT", "Compiling method from bytecode: " + methodName); + private final String scratchReg1; + private final String scratchReg2; - operandStack.clear(); - dataSection.clear(); - registerManager.reset(); - memoryAccessCompiler.reset(); - dataLabelCounter = 0; - this.currentMethodName = methodName; - this.currentMethodBytecode = bytecode; - this.currentPc = 0; - this.currentLoopDepth = 0; + public final RegisterManager registerManager; + private final RegisterManager.RegisterSpiller spiller; - List tempAssemblyCode = new ArrayList(); - List originalAssemblyCodeRef = this.assemblyCode; - setAssemblyTarget(tempAssemblyCode); + private List assemblyCode = new ArrayList(); + private final List dataSection = new ArrayList(); - registerAllocator.markRegisterUsed(this.thisRegister); - spiller.updateRegisterDefinitionDepth(this.thisRegister, 0); + private int dataLabelCounter = 0; + private String currentMethodName = ""; + + public MTOTNativeCompiler(CPUProfile cpuProfile) { + this.cpuProfile = cpuProfile; + this.argumentRegisters = cpuProfile.registerFile.argumentRegisters; - int maxParamsInRegs; - int argStartIndex; if (cpuProfile.architecture.equals("aarch64")) { - maxParamsInRegs = argumentRegisters.size() - 1; - argStartIndex = 1; + this.thisRegister = x19; + this.scratchReg1 = x9; + this.scratchReg2 = x10; + this.abiCallerSavedSet = + new HashSet( + Arrays.asList( + x0, x1, x2, x3, x4, x5, x6, x7, x9, x10, x11, x12, x13, x14, x15, x16, x17)); } else { - maxParamsInRegs = (argumentRegisters.contains(x86_64Registers.rax)) ? - argumentRegisters.size() - 1 : - argumentRegisters.size(); - argStartIndex = 0; + this.thisRegister = r15; + this.scratchReg1 = r10; + this.scratchReg2 = r11; + this.abiCallerSavedSet = + new HashSet(Arrays.asList(rax, rcx, rdx, rsi, rdi, r8, r9, r10, r11)); } - for (int i = 0; i < maxParamsInRegs; i++) { - String argReg = argumentRegisters.get(i + argStartIndex); - registerAllocator.markRegisterUsed(argReg); - spiller.updateRegisterDefinitionDepth(argReg, 0); - } + this.registerManager = new RegisterManager(this); + this.spiller = this.registerManager.getSpiller(); + } - compileFromBytecode(bytecode, new HashMap()); + public String compileMethodFromTAC(String methodName, List tac) { + DebugSystem.info("MTOT", "Compiling method: " + methodName + " (" + tac.size() + " TAC instr)"); - setAssemblyTarget(originalAssemblyCodeRef); + assemblyCode.clear(); + dataSection.clear(); + registerManager.reset(); + dataLabelCounter = 0; + this.currentMethodName = methodName; - Set usedCalleeSavedRegs = new HashSet(); - Set writtenRegisters = spiller.getWrittenRegistersDuringCompilation(); - writtenRegisters.retainAll(this.calleeSavedSet); - usedCalleeSavedRegs.addAll(writtenRegisters); - - if (registerAllocator.getUsedRegisters().contains(this.thisRegister)) { - usedCalleeSavedRegs.add(this.thisRegister); + // FIX: Pass the ABI caller-saved registers to the RegisterManager's graph + // BEFORE running allocation. + this.registerManager.setCallerSavedRegisters(this.abiCallerSavedSet); + + registerManager.runAllocation(tac); + compileBody(tac); + return constructFinalAssembly(methodName); + } + + private void compileBody(List tac) { + Map labelMap = new HashMap(); + for (TACInstruction instr : tac) { + if (instr.opcode == Opcode.LABEL) { + labelMap.put((String) instr.operand1, "L_" + currentMethodName + "_" + instr.operand1); + } } - List calleeSavedToSave = new ArrayList(usedCalleeSavedRegs); - Collections.sort(calleeSavedToSave); + for (int i = 0; i < tac.size(); i++) { + TACInstruction instr = tac.get(i); + + try { + switch (instr.opcode) { + case LABEL: + assemblyCode.add(labelMap.get((String) instr.operand1) + ":"); + break; + + case ASSIGN: + String src = getPhysReg(instr.operand1, scratchReg1, true); + String dest = getPhysReg(instr.result, scratchReg2, false); + if (!src.equals(dest)) emitMove(dest, src); + commitSpill(instr.result, dest); + break; + + case LOAD_IMM: + String immDest = getPhysReg(instr.result, scratchReg1, false); + int val = 0; + if (instr.operand1 instanceof Integer) val = (Integer) instr.operand1; + else if (instr.operand1 instanceof Boolean) val = ((Boolean) instr.operand1) ? 1 : 0; + + String asm = + cpuProfile + .getPattern("load_immediate_int") + .assemblyTemplate + .get(0) + .replace("{dest}", immDest) + .replace("{value}", String.valueOf(val)); + assemblyCode.add(" " + asm); + commitSpill(instr.result, immDest); + break; + + case LOAD_ADDR: + String addrDest = getPhysReg(instr.result, scratchReg1, false); + String dataLabel = generateDataLabel("str"); + dataSection.add( + cpuProfile + .syntax + .stringDirective + .replace("{label}", dataLabel) + .replace("{value}", escapeString((String) instr.operand1))); + for (String t : cpuProfile.getPattern("load_address").assemblyTemplate) { + assemblyCode.add( + " " + t.replace("{dest}", addrDest).replace("{label}", dataLabel)); + } + commitSpill(instr.result, addrDest); + break; + + case ADD: + case SUB: + case MUL: + case DIV: + case MOD: + case CMP_EQ: + case CMP_NE: + case CMP_LT: + case CMP_LE: + case CMP_GT: + case CMP_GE: + compileBinaryOp(instr); + break; + + case INT_TO_STRING: + case CONCAT: + compileStringOp(instr); + break; + + case NEG: + String negSrc = getPhysReg(instr.operand1, scratchReg1, true); + String negDest = getPhysReg(instr.result, scratchReg2, false); + for (String t : cpuProfile.getPattern("neg_int").assemblyTemplate) { + assemblyCode.add(" " + t.replace("{dest}", negDest).replace("{src}", negSrc)); + } + commitSpill(instr.result, negDest); + break; + + case GOTO: + assemblyCode.add( + " " + + cpuProfile + .getPattern("jmp") + .assemblyTemplate + .get(0) + .replace("{label}", labelMap.get((String) instr.operand1))); + break; + + case IF_GOTO: + String ifCond = + getPhysReg( + instr.result, scratchReg1, true); // Sometimes cond is result in TAC struct + String ifLabel = labelMap.get((String) instr.operand2); + if (cpuProfile.architecture.equals("aarch64")) { + assemblyCode.add(" cmp " + ifCond + ", #0"); + assemblyCode.add(" b.eq " + ifLabel); + } else { + assemblyCode.add(" test " + ifCond + ", " + ifCond); + assemblyCode.add(" jz " + ifLabel); + } + break; - int spillAreaSize = spiller.getTotalSpillSize(); - int calleeSavedAreaSize; - if (cpuProfile.architecture.equals("aarch64")) { - calleeSavedAreaSize = calleeSavedToSave.size() * 8; - } else { - calleeSavedAreaSize = 0; + case RET: + if (instr.operand1 != null) { + String retSrc = getPhysReg(instr.operand1, scratchReg1, true); + String abiRet = cpuProfile.architecture.equals("x86_64") ? rax : x0; + if (!retSrc.equals(abiRet)) emitMove(abiRet, retSrc); + } + break; + + case CALL: + case CALL_SLOTS: + compileCall(instr, i, tac); + break; + + case PRINT: + compileRuntimeCall("runtime_print", new String[] {(String) instr.operand1}, false); + break; + + case READ_INPUT: + compileReadInput(instr.result, (String) instr.operand1); + break; + + case ARRAY_NEW: + compileRuntimeCall("array_new", new String[] {(String) instr.operand1}, true); + if (instr.result != null) { + String retReg = cpuProfile.architecture.equals("x86_64") ? rax : x0; + String d = getPhysReg(instr.result, scratchReg1, false); + emitMove(d, retReg); + commitSpill(instr.result, d); + } + break; + + case LOAD_ARRAY: + compileRuntimeCall( + "array_load", + new String[] {(String) instr.operand1, (String) instr.operand2}, + true); + String laRet = cpuProfile.architecture.equals("x86_64") ? rax : x0; + String laDest = getPhysReg(instr.result, scratchReg1, false); + emitMove(laDest, laRet); + commitSpill(instr.result, laDest); + break; + + case STORE_ARRAY: + compileRuntimeCall( + "array_store", + new String[] {(String) instr.operand1, (String) instr.operand2, instr.result}, + false); + break; + + case PARAM: + break; + default: + DebugSystem.warn("MTOT", "Ignored TAC: " + instr.opcode); + } + } catch (Exception e) { + DebugSystem.error("MTOT", "Error compiling " + instr + ": " + e.getMessage()); + } } - - int sizeBelowFp = calleeSavedAreaSize + spillAreaSize; - int alignedSizeBelowFp = (sizeBelowFp + 15) & ~15; - - List finalAssembly = new ArrayList(); - - if (!dataSection.isEmpty()) { - finalAssembly.add(cpuProfile.syntax.dataSection); - finalAssembly.addAll(dataSection); + } + + private void compileBinaryOp(TACInstruction instr) { + String pName; + switch (instr.opcode) { + case ADD: + pName = "add_int"; + break; + case SUB: + pName = "sub_int"; + break; + case MUL: + pName = "mul_int"; + break; + case DIV: + pName = "div_int"; + break; + case MOD: + pName = "mod_int"; + break; + case CMP_EQ: + pName = "cmp_eq_int"; + break; + case CMP_NE: + pName = "cmp_ne_int"; + break; + case CMP_LT: + pName = "cmp_lt_int"; + break; + case CMP_LE: + pName = "cmp_le_int"; + break; + case CMP_GT: + pName = "cmp_gt_int"; + break; + case CMP_GE: + pName = "cmp_ge_int"; + break; + default: + return; } - finalAssembly.add(cpuProfile.syntax.textSection); - - if (cpuProfile.architecture.equals("x86_64")) { - finalAssembly.add(" " + cpuProfile.syntax.commentMarker + " NASM requires extern declarations for runtime functions"); - finalAssembly.add(" extern runtime_print"); - finalAssembly.add(" extern string_concat"); - finalAssembly.add(" extern runtime_int_to_string"); - finalAssembly.add(" extern array_new"); - finalAssembly.add(" extern array_load"); - finalAssembly.add(" extern array_store"); - finalAssembly.add(" extern runtime_read_input"); - finalAssembly.add(""); - } - - finalAssembly.add(cpuProfile.syntax.globalDirective.replace("{name}", methodName)); - finalAssembly.add(methodName + ":"); - - InstructionPattern prologuePattern = cpuProfile.getPattern("prologue"); - if (prologuePattern == null) throw new RuntimeException("Missing 'prologue' pattern!"); - for (String template : prologuePattern.assemblyTemplate) { - finalAssembly.add(" " + template); - } + InstructionPattern p = cpuProfile.getPattern(pName); + String r1 = getPhysReg(instr.operand1, scratchReg1, true); + String r2 = getPhysReg(instr.operand2, scratchReg2, true); + String rDest = getPhysReg(instr.result, scratchReg1, false); - if (cpuProfile.architecture.equals("aarch64")) { - if (alignedSizeBelowFp > 0) { - String asm = cpuProfile.getPattern("alloc_stack_frame").assemblyTemplate.get(0) - .replace("{size}", String.valueOf(alignedSizeBelowFp)); - finalAssembly.add(" " + asm); - } - - int currentCalleeSaveOffset = -16; - if (!calleeSavedToSave.isEmpty()) { - finalAssembly.add(" " + cpuProfile.syntax.commentMarker + " Saving callee-saved registers: " + calleeSavedToSave); - InstructionPattern savePair = cpuProfile.getPattern("save_callee_reg_pair"); - InstructionPattern saveSingle = cpuProfile.getPattern("save_callee_reg_single"); - - for (int i = 0; i < calleeSavedToSave.size(); i += 2) { - if (i + 1 < calleeSavedToSave.size()) { - finalAssembly.add(" " + savePair.assemblyTemplate.get(0) - .replace("{reg1}", calleeSavedToSave.get(i)) - .replace("{reg2}", calleeSavedToSave.get(i+1)) - .replace("{offset}", String.valueOf(currentCalleeSaveOffset))); - } else { - finalAssembly.add(" " + saveSingle.assemblyTemplate.get(0) - .replace("{reg1}", calleeSavedToSave.get(i)) - .replace("{offset}", String.valueOf(currentCalleeSaveOffset))); - } - currentCalleeSaveOffset -= 16; + for (String t : p.assemblyTemplate) { + assemblyCode.add( + " " + t.replace("{dest}", rDest).replace("{src1}", r1).replace("{src2}", r2)); + } + commitSpill(instr.result, rDest); + } + + private void compileStringOp(TACInstruction instr) { + switch (instr.opcode) { + case INT_TO_STRING: { + String src = getPhysReg(instr.operand1, scratchReg1, true); + // Pass integer in argument register 0 + String argReg0 = argumentRegisters.get(0); + if (!src.equals(argReg0)) { + emitMove(argReg0, src); } - } - spiller.setBaseSpillOffset(currentCalleeSaveOffset + 8); - - } else { - int x86SpillAreaSize = (spiller.getTotalSpillSize() + 15) & ~15; - - if (!calleeSavedToSave.isEmpty()) { - finalAssembly.add(" " + cpuProfile.syntax.commentMarker + " Saving callee-saved registers: " + calleeSavedToSave); - InstructionPattern saveSingle = cpuProfile.getPattern("save_callee_reg_single"); - if (saveSingle.assemblyTemplate.isEmpty()) throw new RuntimeException("Missing 'save_callee_reg_single' pattern for x86!"); - for (String reg : calleeSavedToSave) { - finalAssembly.add(" " + saveSingle.assemblyTemplate.get(0).replace("{reg}", reg)); + // Call runtime function to convert int to string + assemblyCode.add(" " + cpuProfile.getPattern("call").assemblyTemplate.get(0) + .replace("{name}", "int_to_string")); + // Get return value + String retReg = cpuProfile.architecture.equals("x86_64") ? rax : x0; + String dest = getPhysReg(instr.result, scratchReg1, false); + if (!dest.equals(retReg)) { + emitMove(dest, retReg); } + commitSpill(instr.result, dest); + break; } - - if (x86SpillAreaSize > 0) { - String asm = cpuProfile.getPattern("alloc_stack_frame").assemblyTemplate.get(0) - .replace("{size}", String.valueOf(x86SpillAreaSize)); - finalAssembly.add(" " + asm); - } - spiller.setBaseSpillOffset(-8); - } - - finalAssembly.add(" mov " + this.thisRegister + ", " + argumentRegisters.get(0) + " " + cpuProfile.syntax.commentMarker + " Copy 'this' pointer"); - - finalAssembly.addAll(tempAssemblyCode); - - Map slotLocations = memoryAccessCompiler.getSlotLocations(); - String returnReg0 = (cpuProfile.architecture.equals("x86_64")) ? x86_64Registers.rax : argumentRegisters.get(0); - - if (!slotLocations.isEmpty()) { - List sortedSlotIndices = new ArrayList(slotLocations.keySet()); - Collections.sort(sortedSlotIndices); - int returnRegIndex = 0; - - for (Integer slotIndex : sortedSlotIndices) { - String abiReturnReg; - if (cpuProfile.architecture.equals("x86_64")) { - if (returnRegIndex == 0) abiReturnReg = x86_64Registers.rax; - else if (returnRegIndex == 1) abiReturnReg = x86_64Registers.rdx; - else break; - } else { - if (returnRegIndex >= argumentRegisters.size()) break; - abiReturnReg = argumentRegisters.get(returnRegIndex); - } - String valueLocation = slotLocations.get(slotIndex); - if (valueLocation.startsWith("spill_")) { - int offset = Integer.parseInt(valueLocation.substring("spill_".length())); - spiller.fillRegisterFromOffset(abiReturnReg, offset); - } else { - spiller.fillRegister(valueLocation); - if (!valueLocation.equals(abiReturnReg)) { - finalAssembly.add(" mov " + abiReturnReg + ", " + valueLocation); - } + case CONCAT: { + String str1 = getPhysReg(instr.operand1, scratchReg1, true); + String str2 = getPhysReg(instr.operand2, scratchReg2, true); + // Pass strings in argument registers 0 and 1 + String argReg0 = argumentRegisters.get(0); + String argReg1 = argumentRegisters.get(1); + if (!str1.equals(argReg0)) { + emitMove(argReg0, str1); } - spiller.markRegisterModified(abiReturnReg); - registerAllocator.markRegisterUsed(abiReturnReg); - returnRegIndex++; - } - DebugSystem.debug("MTOT", "Method " + methodName + " returning " + sortedSlotIndices.size() + " slot values"); - } - else if (!operandStack.isEmpty()) { - String retValReg = operandStack.popToRegister(); - spiller.fillRegister(retValReg); - - String abiReturnReg = returnReg0; - - if (!retValReg.equals(abiReturnReg)) { - finalAssembly.add(" mov " + abiReturnReg + ", " + retValReg); - spiller.markRegisterModified(abiReturnReg); - registerAllocator.freeRegister(retValReg); - } else { - spiller.markRegisterModified(abiReturnReg); + if (!str2.equals(argReg1)) { + emitMove(argReg1, str2); + } + // Call runtime function to concatenate strings + assemblyCode.add(" " + cpuProfile.getPattern("call").assemblyTemplate.get(0) + .replace("{name}", "string_concat")); + // Get return value + String retReg = cpuProfile.architecture.equals("x86_64") ? rax : x0; + String dest = getPhysReg(instr.result, scratchReg1, false); + if (!dest.equals(retReg)) { + emitMove(dest, retReg); + } + commitSpill(instr.result, dest); + break; } - registerAllocator.markRegisterUsed(abiReturnReg); - DebugSystem.debug("MTOT", "Method " + methodName + " returning single value from stack"); - } - else { - String abiReturnReg = returnReg0; - InstructionPattern p = cpuProfile.getPattern("load_immediate_int"); - finalAssembly.add(" " + p.assemblyTemplate.get(0).replace("{dest}", abiReturnReg).replace("{value}", "0") + " " + cpuProfile.syntax.commentMarker + " Default return 0"); - spiller.markRegisterModified(abiReturnReg); - DebugSystem.debug("MTOT", "Method " + methodName + " returning default value 0"); } +} - InstructionPattern epiloguePattern = cpuProfile.getPattern("epilogue"); - if (epiloguePattern == null) throw new RuntimeException("Missing 'epilogue' pattern!"); - - if (cpuProfile.architecture.equals("aarch64")) { - if (!calleeSavedToSave.isEmpty()) { - finalAssembly.add(" " + cpuProfile.syntax.commentMarker + " Restoring callee-saved registers: " + calleeSavedToSave); - InstructionPattern restorePair = cpuProfile.getPattern("restore_callee_reg_pair"); - InstructionPattern restoreSingle = cpuProfile.getPattern("restore_callee_reg_single"); - int calleeSaveSlots = (calleeSavedToSave.size() / 2) + (calleeSavedToSave.size() % 2); - int currentCalleeSaveOffset = -16 - (calleeSaveSlots - 1) * 16; - - for (int i = 0; i < calleeSavedToSave.size(); i += 2) { - if (i + 1 < calleeSavedToSave.size()) { - finalAssembly.add(" " + restorePair.assemblyTemplate.get(0) - .replace("{reg1}", calleeSavedToSave.get(i)) - .replace("{reg2}", calleeSavedToSave.get(i+1)) - .replace("{offset}", String.valueOf(currentCalleeSaveOffset))); - } else { - finalAssembly.add(" " + restoreSingle.assemblyTemplate.get(0) - .replace("{reg1}", calleeSavedToSave.get(i)) - .replace("{offset}", String.valueOf(currentCalleeSaveOffset))); - } - currentCalleeSaveOffset += 16; - } - } - - if (alignedSizeBelowFp > 0) { - finalAssembly.add(" " + epiloguePattern.assemblyTemplate.get(0)); - } - - for (int i = 1; i < epiloguePattern.assemblyTemplate.size(); i++) { - finalAssembly.add(" " + epiloguePattern.assemblyTemplate.get(i)); - } + private void compileCall(TACInstruction instr, int index, List tac) { + String methodName; + int numArgs; + // Check if this is CALL or CALL_SLOTS + if (instr.opcode == Opcode.CALL_SLOTS) { + // For CALL_SLOTS, operand1 is method name, operand2 is arg count + methodName = (String) instr.operand1; + numArgs = (Integer) instr.operand2; } else { - int x86SpillAreaSize = (spiller.getTotalSpillSize() + 15) & ~15; - - finalAssembly.add(" " + epiloguePattern.assemblyTemplate.get(0)); - - if (!calleeSavedToSave.isEmpty()) { - finalAssembly.add(" " + cpuProfile.syntax.commentMarker + " Restoring callee-saved registers: " + calleeSavedToSave); - InstructionPattern restoreSingle = cpuProfile.getPattern("restore_callee_reg_single"); - List reversedSaves = new ArrayList<>(calleeSavedToSave); - Collections.reverse(reversedSaves); - for (String reg : reversedSaves) { - finalAssembly.add(" " + restoreSingle.assemblyTemplate.get(0).replace("{reg}", reg)); - } - } - - for (int i = 1; i < epiloguePattern.assemblyTemplate.size(); i++) { - finalAssembly.add(" " + epiloguePattern.assemblyTemplate.get(i)); - } + // Regular CALL + methodName = (String) instr.operand1; + numArgs = (Integer) instr.operand2; } - operandStack.clear(); - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < finalAssembly.size(); i++) { - sb.append(finalAssembly.get(i)); - if (i < finalAssembly.size() - 1) { - sb.append("\n"); - } + // Collect arguments from preceding PARAM instructions + Stack args = new Stack(); + for (int k = index - 1; k >= 0 && args.size() < numArgs; k--) { + if (tac.get(k).opcode == Opcode.PARAM) { + args.push((String) tac.get(k).operand1); + } } - return sb.toString(); -} - private void setAssemblyTarget(List targetList) { - try { - Field listField = MTOTNativeCompiler.class.getDeclaredField("assemblyCode"); - listField.setAccessible(true); - listField.set(this, targetList); - } catch (Exception e) { - throw new RuntimeException("Failed to swap assembly target list via reflection", e); + // Pass arguments in registers + List abiRegs = argumentRegisters; + int abiIdx = 0; + while (!args.isEmpty()) { + String argTemp = args.pop(); + if (abiIdx < abiRegs.size()) { + String srcReg = getPhysReg(argTemp, scratchReg1, true); + if (!srcReg.equals(abiRegs.get(abiIdx))) { + emitMove(abiRegs.get(abiIdx), srcReg); } + abiIdx++; + } } - private void compileFromBytecode(List bytecode, Map localRegisterMap) { - Map labelNameMap = new HashMap(); - Map> addressToLabelMap = new HashMap>(); - int assemblyLabelCounter = 0; - for (int i = 0; i < bytecode.size(); i++) { - BytecodeInstruction instr = bytecode.get(i); - if (instr.opcode == BytecodeInstruction.Opcode.LABEL) { - String bytecodeLabel = (String) instr.operand; - String assemblyLabel = "L_" + this.currentMethodName + "_" + (assemblyLabelCounter++); - labelNameMap.put(bytecodeLabel, assemblyLabel); - int targetAddress = i; - if (!addressToLabelMap.containsKey(targetAddress)) { - addressToLabelMap.put(targetAddress, new ArrayList()); - } - addressToLabelMap.get(targetAddress).add(assemblyLabel); - } - } + // Pass 'this' pointer + emitMove(abiRegs.get(0), thisRegister); - for (int i = 0; i < bytecode.size(); i++) { - this.currentPc = i; - - if (addressToLabelMap.containsKey(i)) { - for(String label : addressToLabelMap.get(i)) { - assemblyCode.add(label + ":"); - if (label.contains("loop_start") || label.contains("loop_body")) { - currentLoopDepth++; - DebugSystem.debug("LOOP_DEPTH", "Entered loop, depth = " + currentLoopDepth + " at label " + label); - } else if (label.contains("loop_end")) { - if (currentLoopDepth > 0) { - currentLoopDepth--; - DebugSystem.debug("LOOP_DEPTH", "Exited loop, depth = " + currentLoopDepth + " at label " + label); - } else { - DebugSystem.warn("LOOP_DEPTH", "Attempted to exit loop at depth 0, label " + label); - } - } - } - } + // Emit call instruction + assemblyCode.add( + " " + + cpuProfile.getPattern("call").assemblyTemplate.get(0).replace("{name}", methodName)); - BytecodeInstruction instr = bytecode.get(i); - try { - switch (instr.opcode) { - case PUSH_INT: memoryAccessCompiler.compilePushInt((Integer) instr.operand); break; - case PUSH_FLOAT: memoryAccessCompiler.compilePushFloat((Float) instr.operand); break; - case PUSH_STRING: memoryAccessCompiler.compilePushString((String) instr.operand); break; - case PUSH_BOOL: memoryAccessCompiler.compilePushInt(((Boolean) instr.operand) ? 1 : 0); break; - case PUSH_NULL: memoryAccessCompiler.compilePushNull(); break; - case POP: memoryAccessCompiler.compilePop(); break; - case DUP: memoryAccessCompiler.compileDup(); break; - case SWAP: memoryAccessCompiler.compileSwap(); break; - case STORE_LOCAL: memoryAccessCompiler.compileStoreLocal((Integer) instr.operand, localRegisterMap); break; - case LOAD_LOCAL: memoryAccessCompiler.compileLoadLocal((Integer) instr.operand, localRegisterMap); break; - case LOAD_FIELD: memoryAccessCompiler.compileLoadField((String) instr.operand); break; - case STORE_FIELD: memoryAccessCompiler.compileStoreField((String) instr.operand); break; - case STORE_SLOT: memoryAccessCompiler.compileStoreSlot(instr.operand, localRegisterMap); break; - - case ADD_INT: operationCompiler.generateBinaryOp("add_int"); break; - case SUB_INT: operationCompiler.generateBinaryOp("sub_int"); break; - case MUL_INT: operationCompiler.generateBinaryOp("mul_int"); break; - case DIV_INT: operationCompiler.generateBinaryOp("div_int"); break; - case MOD_INT: operationCompiler.generateBinaryOp("mod_int"); break; - case NEG_INT: operationCompiler.generateUnaryOp("neg_int"); break; - - case CMP_EQ_INT: operationCompiler.generateBinaryOp("cmp_eq_int"); break; - case CMP_NE_INT: operationCompiler.generateBinaryOp("cmp_ne_int"); break; - case CMP_LT_INT: operationCompiler.generateBinaryOp("cmp_lt_int"); break; - case CMP_LE_INT: operationCompiler.generateBinaryOp("cmp_le_int"); break; - case CMP_GT_INT: operationCompiler.generateBinaryOp("cmp_gt_int"); break; - case CMP_GE_INT: operationCompiler.generateBinaryOp("cmp_ge_int"); break; - - case JMP: controlFlowCompiler.compileJmp(labelNameMap.get((String)instr.operand)); break; - case JMP_IF_TRUE: controlFlowCompiler.compileJmpIfTrue(labelNameMap.get((String)instr.operand)); break; - case JMP_IF_FALSE:controlFlowCompiler.compileJmpIfFalse(labelNameMap.get((String)instr.operand)); break; - case LABEL: break; - case RET: break; - - case CALL: methodCallCompiler.compileCall(instr, bytecode, i, localRegisterMap); break; - case CALL_SLOTS: methodCallCompiler.compileCallSlots(instr, bytecode, i, localRegisterMap); break; - - case PRINT: runtimeCallHelper.compileRuntimeCall("runtime_print", 1, false); break; - case CONCAT_STRING: runtimeCallHelper.compileRuntimeCall("string_concat", 2, true); break; - case INT_TO_STRING: runtimeCallHelper.compileRuntimeCall("runtime_int_to_string", 1, true); break; - case ARRAY_NEW: runtimeCallHelper.compileRuntimeCall("array_new", 1, true); break; - case ARRAY_LOAD: runtimeCallHelper.compileRuntimeCall("array_load", 2, true); break; - case ARRAY_STORE: runtimeCallHelper.compileRuntimeCall("array_store", 3, false); break; - case READ_INPUT: runtimeCallHelper.compileReadInput((String) instr.operand); break; - - default: - DebugSystem.warn("MTOT", "Unhandled bytecode instruction: " + instr.opcode); - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " Unhandled: " + instr.opcode); - break; - } - } catch (Exception e) { - DebugSystem.error("MTOT", "Error compiling instruction " + i + ": " + instr.opcode + " ("+instr.operand+") - " + e.getMessage()); - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " ERROR compiling " + instr.opcode + ": " + e.getMessage()); - e.printStackTrace(); - } - } + // Handle return value + if (instr.result != null) { + String retReg = cpuProfile.architecture.equals("x86_64") ? rax : x0; + String dest = getPhysReg(instr.result, scratchReg1, false); + emitMove(dest, retReg); + commitSpill(instr.result, dest); } - - public String escapeString(String str) { - str = str.replace("\\", "\\\\"); - str = str.replace("\"", "\\\""); - str = str.replace("\n", "\\n"); - str = str.replace("\t", "\\t"); - str = str.replace("\0", "\\0"); - return str; + } + + private void compileRuntimeCall(String name, String[] argTemps, boolean hasRet) { + List abiRegs = argumentRegisters; + for (int i = 0; i < argTemps.length; i++) { + if (argTemps[i] == null) continue; + String src = getPhysReg(argTemps[i], scratchReg1, true); + emitMove(abiRegs.get(i), src); } - - public String generateDataLabel(String prefix) { - return prefix + "_" + this.currentMethodName + "_" + (dataLabelCounter++); + assemblyCode.add( + " " + cpuProfile.getPattern("call").assemblyTemplate.get(0).replace("{name}", name)); + } + + private void compileReadInput(String resultTemp, String typeStr) { + String dataLabel = generateDataLabel("type"); + dataSection.add( + cpuProfile + .syntax + .stringDirective + .replace("{label}", dataLabel) + .replace("{value}", escapeString(typeStr))); + String arg0 = argumentRegisters.get(0); + for (String t : cpuProfile.getPattern("load_address").assemblyTemplate) { + assemblyCode.add(" " + t.replace("{dest}", arg0).replace("{label}", dataLabel)); } - - public void generateSpillCode(String register, int offset) { - int finalOffset = offset; - String baseReg = (cpuProfile.architecture.equals("x86_64")) ? x86_64Registers.rbp : AArch64Registers.fp; - if (cpuProfile.architecture.equals("x86_64")) { - if (offset > 0) finalOffset = -offset; - baseReg = x86_64Registers.rbp; - } else { - baseReg = AArch64Registers.fp; - } - - InstructionPattern pattern = cpuProfile.getPattern("store_to_stack"); - if (pattern == null) { throw new RuntimeException("Missing 'store_to_stack' instruction pattern for architecture: " + cpuProfile.architecture); } - String asm = pattern.assemblyTemplate.get(0) - .replace("{src_reg}", register) - .replace("{offset}", String.valueOf(finalOffset)); - - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " Spill " + register + " to [" + baseReg + ((finalOffset < 0) ? "" : "+") + finalOffset + "]"); - assemblyCode.add(" " + asm); + assemblyCode.add( + " " + + cpuProfile + .getPattern("call") + .assemblyTemplate + .get(0) + .replace("{name}", "runtime_read_input")); + String retReg = cpuProfile.architecture.equals("x86_64") ? rax : x0; + String dest = getPhysReg(resultTemp, scratchReg1, false); + emitMove(dest, retReg); + commitSpill(resultTemp, dest); + } + + private String getPhysReg(Object operand, String scratchReg, boolean loadIfSpilled) { + if (!(operand instanceof String)) return scratchReg; + String temp = (String) operand; + String reg = registerManager.getRegister(temp); + if (reg != null) return reg; + + Integer offset = spiller.getSpillOffset(temp); + if (offset == null) { + spiller.forceSpill(temp); + offset = spiller.getSpillOffset(temp); } - public void generateFillCode(String register, int offset) { - int finalOffset = offset; - String baseReg = (cpuProfile.architecture.equals("x86_64")) ? x86_64Registers.rbp : AArch64Registers.fp; - if (cpuProfile.architecture.equals("x86_64")) { - if (offset > 0) finalOffset = -offset; - baseReg = x86_64Registers.rbp; - } else { - baseReg = AArch64Registers.fp; - } - - InstructionPattern pattern = cpuProfile.getPattern("load_from_stack"); - if (pattern == null) { throw new RuntimeException("Missing 'load_from_stack' instruction pattern for architecture: " + cpuProfile.architecture); } - String asm = pattern.assemblyTemplate.get(0) - .replace("{dest_reg}", register) - .replace("{offset}", String.valueOf(finalOffset)); - - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " Fill " + register + " from [" + baseReg + ((finalOffset < 0) ? "" : "+") + finalOffset + "]"); - assemblyCode.add(" " + asm); + if (loadIfSpilled) { + String asm = + cpuProfile + .getPattern("load_from_stack") + .assemblyTemplate + .get(0) + .replace("{dest_reg}", scratchReg) + .replace("{offset}", String.valueOf(Math.abs(offset))); + assemblyCode.add(" " + asm); } - - public Set spillCallerSavedRegisters(Set excludeArgs) { - Set currentlyLiveRegs = registerAllocator.getUsedRegisters(); - Set callerSavedToSpill = new HashSet(); - - callerSavedToSpill.addAll(currentlyLiveRegs); - callerSavedToSpill.retainAll(this.abiCallerSavedSet); - - if (excludeArgs != null) { - callerSavedToSpill.removeAll(excludeArgs); - } - - if (!callerSavedToSpill.isEmpty()) { - List orderedSpill = new ArrayList(callerSavedToSpill); - Collections.sort(orderedSpill); - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " Spilling caller-saved registers before call: " + orderedSpill); - for (String reg : orderedSpill) { - if (registerAllocator.usedRegisters.contains(reg)){ - spiller.forceSpill(reg); - } - } - } else { - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " No caller-saved registers needed spilling before call."); - } - return callerSavedToSpill; + return scratchReg; + } + + private void commitSpill(String temp, String srcReg) { + if (registerManager.getRegister(temp) != null) return; + Integer offset = spiller.getSpillOffset(temp); + String asm = + cpuProfile + .getPattern("store_to_stack") + .assemblyTemplate + .get(0) + .replace("{src_reg}", srcReg) + .replace("{offset}", String.valueOf(Math.abs(offset))); + assemblyCode.add(" " + asm); + } + + private void emitMove(String dest, String src) { + if (dest.equals(src)) return; + assemblyCode.add( + " " + + cpuProfile + .getPattern("move_reg") + .assemblyTemplate + .get(0) + .replace("{dest}", dest) + .replace("{src}", src)); + } + + private String constructFinalAssembly(String methodName) { + List finalAsm = new ArrayList(); + if (!dataSection.isEmpty()) { + finalAsm.add(cpuProfile.syntax.dataSection); + finalAsm.addAll(dataSection); } + finalAsm.add(cpuProfile.syntax.textSection); + if (cpuProfile.architecture.equals("x86_64")) { + finalAsm.add(" global " + methodName); + finalAsm.add( + " extern runtime_print, int_to_string, string_concat, array_new, array_load, array_store, runtime_read_input"); + } else { + finalAsm.add(" .global " + methodName); + finalAsm.add(" .extern int_to_string"); + finalAsm.add(" .extern string_concat"); + finalAsm.add(" .extern runtime_print"); + finalAsm.add(" .extern runtime_read_input"); + finalAsm.add(" .extern array_new"); + finalAsm.add(" .extern array_load"); + finalAsm.add(" .extern array_store"); + } + finalAsm.add(methodName + ":"); + for (String t : cpuProfile.getPattern("prologue").assemblyTemplate) finalAsm.add(" " + t); + + int stackSize = spiller.getTotalSpillSize(); + if (stackSize > 0) { + finalAsm.add( + " " + + cpuProfile + .getPattern("alloc_stack_frame") + .assemblyTemplate + .get(0) + .replace("{size}", String.valueOf(stackSize))); + } + finalAsm.addAll(assemblyCode); + for (String t : cpuProfile.getPattern("epilogue").assemblyTemplate) finalAsm.add(" " + t); - public void fillCallerSavedRegisters(Set registersToFill) { - if (registersToFill != null && !registersToFill.isEmpty()) { - List orderedRestore = new ArrayList(registersToFill); - Collections.sort(orderedRestore); + StringBuilder sb = new StringBuilder(); + for (String s : finalAsm) sb.append(s).append("\n"); + return sb.toString(); + } - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " Filling caller-saved registers after call: " + orderedRestore); - for (String reg : orderedRestore) { - spiller.fillRegister(reg); - registerAllocator.markRegisterUsed(reg); - } - } else { - assemblyCode.add(" " + cpuProfile.syntax.commentMarker + " No caller-saved registers needed filling after call."); - } - } -} \ No newline at end of file + private String generateDataLabel(String prefix) { + return prefix + "_" + currentMethodName + "_" + (dataLabelCounter++); + } + + private String escapeString(String str) { + return str.replace("\"", "\\\"").replace("\n", "\\n"); + } +} diff --git a/src/main/java/cod/compiler/MTOTRegistry.java b/src/main/java/cod/compiler/MTOTRegistry.java new file mode 100644 index 00000000..37422e75 --- /dev/null +++ b/src/main/java/cod/compiler/MTOTRegistry.java @@ -0,0 +1,122 @@ +package cod.compiler; + +import java.util.*; +import static cod.compiler.MTOTRegistry.AArch64Registers.*; +import static cod.compiler.MTOTRegistry.x86_64Registers.*; + +public class MTOTRegistry { + private static final Map profiles = new HashMap(); + + // --- Added method for manual profile retrieval --- + public static CPUProfile getProfile(String architecture) { + return profiles.get(architecture); + } + // ------------------------------------------------- + + public static class AArch64Registers { + public static final String x19="x19", x20="x20", x21="x21", x22="x22", x23="x23", x24="x24", x25="x25", x26="x26", x27="x27", x28="x28", x29="x29", x30="x30"; + public static final String x9="x9", x10="x10", x11="x11", x12="x12", x13="x13", x14="x14", x15="x15", x16="x16", x17="x17"; + public static final String x0="x0", x1="x1", x2="x2", x3="x3", x4="x4", x5="x5", x6="x6", x7="x7"; + public static final String sp="sp", fp="x29", lr="x30", zr="xzr"; + } + + public static class x86_64Registers { + public static final String rbx="rbx", rbp="rbp", r12="r12", r13="r13", r14="r14", r15="r15"; + public static final String rax="rax", rcx="rcx", rdx="rdx", rsi="rsi", rdi="rdi", r8="r8", r9="r9", r10="r10", r11="r11"; + public static final String rsp="rsp"; + } + + public static class SyntaxProfile { + public final String commentMarker, textSection, dataSection, stringDirective; + public SyntaxProfile(String c, String t, String d, String s) { commentMarker=c; textSection=t; dataSection=d; stringDirective=s; } + } + + public static class InstructionPattern { + public final List assemblyTemplate; + public InstructionPattern(List a) { assemblyTemplate=a; } + } + + public static class RegisterFile { + public final List generalPurpose, argumentRegisters; + public RegisterFile(List gp, List args) { generalPurpose=gp; argumentRegisters=args; } + } + + public static class CPUProfile { + public final String architecture; + public final Map patterns; + public final RegisterFile registerFile; + public final SyntaxProfile syntax; + public CPUProfile(String a, Map p, RegisterFile r, SyntaxProfile s) { architecture=a; patterns=p; registerFile=r; syntax=s; } + public InstructionPattern getPattern(String t) { return patterns.get(t); } + } + + static { + + // --- x86_64 --- + Map x86 = new HashMap(); + x86.put("prologue", new InstructionPattern(Arrays.asList("push " + rbp, "mov " + rbp + ", " + rsp))); + x86.put("epilogue", new InstructionPattern(Arrays.asList("mov " + rsp + ", " + rbp, "pop " + rbp, "ret"))); + x86.put("move_reg", new InstructionPattern(Arrays.asList("mov {dest}, {src}"))); + x86.put("load_immediate_int", new InstructionPattern(Arrays.asList("mov {dest}, {value}"))); + x86.put("load_address", new InstructionPattern(Arrays.asList("lea {dest}, [rel {label}]"))); + x86.put("add_int", new InstructionPattern(Arrays.asList("add {dest}, {src2}"))); + x86.put("sub_int", new InstructionPattern(Arrays.asList("sub {dest}, {src2}"))); + x86.put("mul_int", new InstructionPattern(Arrays.asList("imul {dest}, {src2}"))); + x86.put("div_int", new InstructionPattern(Arrays.asList("mov rax, {dest}", "cqo", "idiv {src2}", "mov {dest}, rax"))); + x86.put("mod_int", new InstructionPattern(Arrays.asList("mov rax, {dest}", "cqo", "idiv {src2}", "mov {dest}, rdx"))); + x86.put("neg_int", new InstructionPattern(Arrays.asList("neg {dest}"))); + x86.put("cmp_eq_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "sete al", "movzx {dest}, al"))); + x86.put("cmp_ne_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "setne al", "movzx {dest}, al"))); + x86.put("cmp_lt_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "setl al", "movzx {dest}, al"))); + x86.put("cmp_le_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "setle al", "movzx {dest}, al"))); + x86.put("cmp_gt_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "setg al", "movzx {dest}, al"))); + x86.put("cmp_ge_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "setge al", "movzx {dest}, al"))); + x86.put("jmp", new InstructionPattern(Arrays.asList("jmp {label}"))); + x86.put("call", new InstructionPattern(Arrays.asList("call {name}"))); + x86.put("store_to_stack", new InstructionPattern(Arrays.asList("mov [" + rbp + " - {offset}], {src_reg}"))); + x86.put("load_from_stack", new InstructionPattern(Arrays.asList("mov {dest_reg}, [" + rbp + " - {offset}]"))); + x86.put("alloc_stack_frame", new InstructionPattern(Arrays.asList("sub " + rsp + ", {size}"))); + + profiles.put("x86_64", new CPUProfile("x86_64", x86, + new RegisterFile(Arrays.asList(rbx, r12, r13, r14, r15), Arrays.asList(rdi, rsi, rdx, rcx, r8, r9)), + new SyntaxProfile(";", "section .text", "section .data", "{label}: db \"{value}\", 0"))); + + // --- AArch64 --- + Map arm = new HashMap(); + arm.put("prologue", new InstructionPattern(Arrays.asList("stp " + fp + ", " + lr + ", [" + sp + ", #-16]!", "mov " + fp + ", " + sp))); + arm.put("epilogue", new InstructionPattern(Arrays.asList("mov " + sp + ", " + fp, "ldp " + fp + ", " + lr + ", [" + sp + "], #16", "ret"))); + arm.put("move_reg", new InstructionPattern(Arrays.asList("mov {dest}, {src}"))); + arm.put("load_immediate_int", new InstructionPattern(Arrays.asList("mov {dest}, #{value}"))); + arm.put("load_address", new InstructionPattern(Arrays.asList("adrp {dest}, {label}", "add {dest}, {dest}, :lo12:{label}"))); + arm.put("add_int", new InstructionPattern(Arrays.asList("add {dest}, {src1}, {src2}"))); + arm.put("sub_int", new InstructionPattern(Arrays.asList("sub {dest}, {src1}, {src2}"))); + arm.put("mul_int", new InstructionPattern(Arrays.asList("mul {dest}, {src1}, {src2}"))); + arm.put("div_int", new InstructionPattern(Arrays.asList("sdiv {dest}, {src1}, {src2}"))); + arm.put("cmp_eq_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "cset {dest}, eq"))); + arm.put("cmp_ne_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "cset {dest}, ne"))); + arm.put("cmp_lt_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "cset {dest}, lt"))); + arm.put("cmp_le_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "cset {dest}, le"))); + arm.put("cmp_gt_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "cset {dest}, gt"))); + arm.put("cmp_ge_int", new InstructionPattern(Arrays.asList("cmp {src1}, {src2}", "cset {dest}, ge"))); + arm.put("jmp", new InstructionPattern(Arrays.asList("b {label}"))); + arm.put("call", new InstructionPattern(Arrays.asList("bl {name}"))); + + // FIX: Use negative offset relative to FP for Store (spilled var) + arm.put("store_to_stack", new InstructionPattern(Arrays.asList("str {src_reg}, [" + fp + ", #-{offset}]"))); + + // FIX: Use negative offset relative to FP for Load (spilled var) + arm.put("load_from_stack", new InstructionPattern(Arrays.asList("ldr {dest_reg}, [" + fp + ", #-{offset}]"))); + + arm.put("alloc_stack_frame", new InstructionPattern(Arrays.asList("sub " + sp + ", " + sp + ", #{size}"))); + + profiles.put("aarch64", new CPUProfile("aarch64", arm, + new RegisterFile(Arrays.asList(x19, x20, x21, x22, x23, x24, x25, x26, x27, x28), Arrays.asList(x0, x1, x2, x3, x4, x5, x6, x7)), + new SyntaxProfile("//", ".text", ".data", "{label}: .asciz \"{value}\""))); + } + + public static CPUProfile detectCPU() { + String arch = System.getProperty("os.arch").toLowerCase(); + if (arch.contains("aarch64") || arch.contains("arm64")) return profiles.get("aarch64"); + return profiles.get("x86_64"); + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/RegisterManager.java b/src/main/java/cod/compiler/RegisterManager.java new file mode 100644 index 00000000..cba574b8 --- /dev/null +++ b/src/main/java/cod/compiler/RegisterManager.java @@ -0,0 +1,89 @@ +package cod.compiler; + +import java.util.*; + +public class RegisterManager { + private final LivenessAnalyzer analyzer; + private final GraphColoringAllocator graphAllocator; + private final RegisterSpiller registerSpiller; + private final MTOTRegistry.RegisterFile registerFile; + + private Map currentAllocation = new HashMap(); + + public RegisterManager(MTOTNativeCompiler compiler) { + this.registerFile = compiler.cpuProfile.registerFile; + this.registerSpiller = new RegisterSpiller(compiler); + this.analyzer = new LivenessAnalyzer(); + this.graphAllocator = new GraphColoringAllocator(registerFile, registerSpiller); + } + + // NEW METHOD: Used by MTOTNativeCompiler to set the registers that CALLs clobber. + public void setCallerSavedRegisters(Set registers) { + this.graphAllocator.getInterferenceGraph().callerSavedRegisters = registers; + } + + public void runAllocation(List instructions) { + registerSpiller.reset(); + + List blocks = analyzer.buildCFG(instructions); + analyzer.computeGlobalLiveness(blocks); + + InterferenceGraph graph = new InterferenceGraph(); + + // Ensure the graph used for building is the one referenced by the allocator + // if they were separate, but since we are replacing the call here: + graph.callerSavedRegisters = this.graphAllocator.getInterferenceGraph().callerSavedRegisters; + + graph.buildFromCFG(blocks); + + this.currentAllocation = graphAllocator.allocate(graph); + } + + public String getRegister(String temp) { + return currentAllocation.get(temp); + } + + public RegisterSpiller getSpiller() { + return registerSpiller; + } + + public void reset() { + registerSpiller.reset(); + currentAllocation.clear(); + } + + public static class RegisterSpiller { + private final MTOTNativeCompiler compiler; + private final Map spillSlots = new HashMap(); + // FIX: Start offset at -24 to clear the 16 bytes of saved FP/LR. + private int nextSpillOffset = -24; + private int totalSpillSize = 0; + + public RegisterSpiller(MTOTNativeCompiler compiler) { + this.compiler = compiler; + } + + public void reset() { + spillSlots.clear(); + totalSpillSize = 0; + // Reset to the new starting offset + nextSpillOffset = -24; + } + + public void forceSpill(String temp) { + if (!spillSlots.containsKey(temp)) { + spillSlots.put(temp, nextSpillOffset); + totalSpillSize += 8; + nextSpillOffset -= 8; + } + } + + public Integer getSpillOffset(String temp) { + return spillSlots.get(temp); + } + + public int getTotalSpillSize() { + return (totalSpillSize + 15) & ~15; + } + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/TACCompiler.java b/src/main/java/cod/compiler/TACCompiler.java new file mode 100644 index 00000000..935033d2 --- /dev/null +++ b/src/main/java/cod/compiler/TACCompiler.java @@ -0,0 +1,697 @@ +package cod.compiler; + +import cod.ast.BaseASTVisitor; +import cod.ast.nodes.*; +import cod.compiler.TACInstruction.Opcode; +import cod.debug.DebugSystem; +import java.util.*; + +public class TACCompiler extends BaseASTVisitor { + + private TACProgram tacProgram; + private List currentCode; + + private Map variableToTempMap = new HashMap(); + private int labelCounter = 0; + private int nextTempId = 0; + private String currentMethodName = ""; + + public TACProgram compile(ProgramNode program) { + DebugSystem.info("TAC", "Starting Visitor-based TAC compilation"); + this.tacProgram = new TACProgram(); + visit(program); + return tacProgram; + } + + private void emit(TACInstruction instr) { + currentCode.add(instr); + } + + private String newTemp() { + return "$t" + (nextTempId++); + } + + private String getNewLabel(String prefix) { + return "L_" + currentMethodName + "_" + prefix + "_" + (labelCounter++); + } + + private String allocateVariable(String name) { + String tacName = "$v_" + name; + variableToTempMap.put(name, tacName); + return tacName; + } + + private String getOrAllocateVariable(String name) { + if (!variableToTempMap.containsKey(name)) { + return allocateVariable(name); + } + return variableToTempMap.get(name); + } + + // --- Structural Visitors --- + + @Override + public String visit(ProgramNode node) { + if (node.unit != null) visit(node.unit); + return null; + } + + @Override + public String visit(UnitNode node) { + for (TypeNode type : node.types) visit(type); + return null; + } + + @Override + public String visit(TypeNode node) { + for (MethodNode method : node.methods) visit(method); + return null; + } + + @Override + public String visit(MethodNode method) { + currentCode = new ArrayList(); + variableToTempMap.clear(); + labelCounter = 0; + nextTempId = 0; + currentMethodName = method.name; + + // Allocate variables for parameters + for (ParamNode param : method.parameters) allocateVariable(param.name); + + // Allocate variables for return slots + for (SlotNode slot : method.returnSlots) allocateVariable(slot.name); + + // Compile method body + for (StmtNode stmt : method.body) visit(stmt); + + // Add implicit return if missing + if (currentCode.isEmpty() || currentCode.get(currentCode.size() - 1).opcode != Opcode.RET) { + if (!method.returnSlots.isEmpty()) { + String firstSlot = variableToTempMap.get(method.returnSlots.get(0).name); + emit(new TACInstruction(Opcode.RET, firstSlot)); + } else { + emit(new TACInstruction(Opcode.RET)); + } + } + + tacProgram.addMethod(method.name, new ArrayList(currentCode)); + return null; + } + + // --- Statement Visitors --- + + @Override + public String visit(VarNode node) { + String targetTemp = getOrAllocateVariable(node.name); + if (node.value != null) { + String valTemp = dispatch(node.value); + if (valTemp != null) { + emit(new TACInstruction(Opcode.ASSIGN, targetTemp, valTemp)); + } + } + return null; + } + + @Override + public String visit(AssignmentNode node) { + if (node.left instanceof IndexAccessNode) { + IndexAccessNode access = (IndexAccessNode) node.left; + String arrTemp = dispatch(access.array); + String idxTemp = dispatch(access.index); + String valTemp = dispatch(node.right); + emit(new TACInstruction(Opcode.STORE_ARRAY, valTemp, arrTemp, idxTemp)); + } + else if (node.left instanceof ExprNode) { + String name = ((ExprNode) node.left).name; + String valTemp = dispatch(node.right); + String targetTemp = getOrAllocateVariable(name); + emit(new TACInstruction(Opcode.ASSIGN, targetTemp, valTemp)); + } + return null; + } + + @Override + public String visit(SlotAssignmentNode node) { + String valTemp = dispatch(node.value); + String targetName = node.slotName; + String targetTemp = getOrAllocateVariable(targetName); + emit(new TACInstruction(Opcode.ASSIGN, targetTemp, valTemp)); + return null; + } + + @Override + public String visit(MultipleSlotAssignmentNode node) { + for (SlotAssignmentNode sub : node.assignments) visit(sub); + return null; + } + + @Override + public String visit(ReturnSlotAssignmentNode node) { + MethodCallNode call = node.methodCall; + + // Step 1: Push all arguments + for (ExprNode arg : call.arguments) { + String t = dispatch(arg); + emit(new TACInstruction(Opcode.PARAM, t)); + } + + // Step 2: Call method - returns primary result (could be array/map) + String primaryRet = newTemp(); + + // Use CALL_SLOTS to indicate this returns multiple values + // Operand1: method name + // Operand2: argument count + // No need for slot count in operand since we handle it in runtime + emit(new TACInstruction(Opcode.CALL_SLOTS, primaryRet, call.qualifiedName, call.arguments.size())); + + // Step 3: Extract each slot to destination variables + for (int i = 0; i < node.variableNames.size(); i++) { + String targetVar = node.variableNames.get(i); + String targetTemp = getOrAllocateVariable(targetVar); + + if (i == 0) { + // First variable gets the primary return + emit(new TACInstruction(Opcode.ASSIGN, targetTemp, primaryRet)); + } else { + // Additional variables from array (if method returns array) + // For now, assume method returns array with slots at indices + String idxTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, idxTemp, i)); + emit(new TACInstruction(Opcode.LOAD_ARRAY, targetTemp, primaryRet, idxTemp)); + } + } + return null; + } + + @Override + public String visit(StmtIfNode node) { + String elseLabel = getNewLabel("else"); + String endLabel = getNewLabel("endif"); + + String condTemp = dispatch(node.condition); + + // Compare condition with 0 (false) + String zeroTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, zeroTemp, 0)); + emit(new TACInstruction(Opcode.IF_GOTO, condTemp, zeroTemp, elseLabel)); + + // Then block + visitBlock(node.thenBlock); + + boolean hasElse = node.elseBlock != null && !node.elseBlock.statements.isEmpty(); + if (hasElse) { + emit(new TACInstruction(Opcode.GOTO, endLabel)); + } + + // Else block + emit(new TACInstruction(Opcode.LABEL, elseLabel)); + if (hasElse) { + visitBlock(node.elseBlock); + } + + emit(new TACInstruction(Opcode.LABEL, endLabel)); + return null; + } + + private void visitBlock(BlockNode block) { + if (block == null) return; + for (StmtNode s : block.statements) visit(s); + } + + @Override + public String visit(ForNode node) { + String iterTemp = getOrAllocateVariable(node.iterator); + + // Evaluate start expression + String startTemp = dispatch(node.range.start); + if (startTemp == null) { + startTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, startTemp, 0)); + } + + // Evaluate end expression + String endTemp = dispatch(node.range.end); + if (endTemp == null) { + endTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, endTemp, 0)); + } + + // Evaluate step expression (or default to 1) + String stepTemp = newTemp(); + if (node.range.step != null) { + String stepVal = dispatch(node.range.step); + if (stepVal != null) { + stepTemp = stepVal; + } else { + emit(new TACInstruction(Opcode.LOAD_IMM, stepTemp, 1)); + } + } else { + emit(new TACInstruction(Opcode.LOAD_IMM, stepTemp, 1)); + } + + emit(new TACInstruction(Opcode.ASSIGN, iterTemp, startTemp)); + + String startLabel = getNewLabel("loop_start"); + String endLabel = getNewLabel("loop_end"); + String checkNegativeLabel = getNewLabel("check_neg"); + String checkDoneLabel = getNewLabel("check_done"); + + emit(new TACInstruction(Opcode.LABEL, startLabel)); + + // --- BEGIN Dynamic Loop Condition Check --- + + // 1. Determine direction: Check if step is positive (>= 0) + String zeroTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, zeroTemp, 0)); + + String isPositive = newTemp(); + emit(new TACInstruction(Opcode.CMP_GE, isPositive, stepTemp, zeroTemp)); + + // If step is NOT positive (i.e., step < 0), jump to check_neg + emit(new TACInstruction(Opcode.IF_GOTO, isPositive, zeroTemp, checkNegativeLabel)); + + // Fallthrough: Positive Step (Check: iter > end -> Break) + String condPos = newTemp(); + emit(new TACInstruction(Opcode.CMP_GT, condPos, iterTemp, endTemp)); + String oneTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, oneTemp, 1)); + emit(new TACInstruction(Opcode.IF_GOTO, condPos, oneTemp, endLabel)); + emit(new TACInstruction(Opcode.GOTO, checkDoneLabel)); // Skip negative check + + // Negative Step Check (Check: iter < end -> Break) + emit(new TACInstruction(Opcode.LABEL, checkNegativeLabel)); + String condNeg = newTemp(); + emit(new TACInstruction(Opcode.CMP_LT, condNeg, iterTemp, endTemp)); + emit(new TACInstruction(Opcode.LOAD_IMM, oneTemp, 1)); // Reuse oneTemp + emit(new TACInstruction(Opcode.IF_GOTO, condNeg, oneTemp, endLabel)); + + emit(new TACInstruction(Opcode.LABEL, checkDoneLabel)); + + // --- END Dynamic Loop Condition Check --- + + // Loop body + visitBlock(node.body); + + // Increment iterator + String nextIter = newTemp(); + // The step variable (stepTemp) holds the value, positive or negative + emit(new TACInstruction(Opcode.ADD, nextIter, iterTemp, stepTemp)); + emit(new TACInstruction(Opcode.ASSIGN, iterTemp, nextIter)); + + emit(new TACInstruction(Opcode.GOTO, startLabel)); + emit(new TACInstruction(Opcode.LABEL, endLabel)); + return null; + } + + @Override + public String visit(OutputNode node) { + if (node.arguments.isEmpty()) { + String t = newTemp(); + emit(new TACInstruction(Opcode.LOAD_ADDR, t, "")); + emit(new TACInstruction(Opcode.PRINT, t)); + return null; + } + + for (ExprNode arg : node.arguments) { + String val = dispatch(arg); + if (val == null) { + // Handle method calls that return void + if (arg instanceof MethodCallNode) { + // Call already emitted, just need PRINT + String temp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, temp, 0)); // Dummy value + emit(new TACInstruction(Opcode.PRINT, temp)); + } + } else { + emit(new TACInstruction(Opcode.PRINT, val)); + } + } + return null; + } + + @Override + public String visit(InputNode node) { + String targetTemp = getOrAllocateVariable(node.variableName); + String typeTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_ADDR, typeTemp, node.targetType)); + emit(new TACInstruction(Opcode.READ_INPUT, targetTemp, typeTemp)); + return null; + } + + @Override + public String visit(BinaryOpNode node) { + System.err.println("DEBUG BinaryOpNode: " + node.op); + + // ALWAYS get values for both operands + String leftTemp = dispatch(node.left); + if (leftTemp == null) { + leftTemp = newTemp(); + System.err.println(" WARNING: left operand returned null, using default"); + emit(new TACInstruction(Opcode.LOAD_IMM, leftTemp, 0)); + } + + String rightTemp = dispatch(node.right); + if (rightTemp == null) { + rightTemp = newTemp(); + System.err.println(" WARNING: right operand returned null, using default"); + emit(new TACInstruction(Opcode.LOAD_IMM, rightTemp, 0)); + } + + String resultTemp = newTemp(); + + // Handle string concatenation + if ("+".equals(node.op)) { + boolean leftIsString = isStringNode(node.left); + boolean rightIsString = isStringNode(node.right); + + if (leftIsString || rightIsString) { + // String concatenation + if (!leftIsString) { + String leftStr = newTemp(); + emit(new TACInstruction(Opcode.INT_TO_STRING, leftStr, leftTemp)); + leftTemp = leftStr; + } + if (!rightIsString) { + String rightStr = newTemp(); + emit(new TACInstruction(Opcode.INT_TO_STRING, rightStr, rightTemp)); + rightTemp = rightStr; + } + emit(new TACInstruction(Opcode.CONCAT, resultTemp, leftTemp, rightTemp)); + return resultTemp; + } + } + + // Handle other binary operations + Opcode opcode = mapOp(node.op); + emit(new TACInstruction(opcode, resultTemp, leftTemp, rightTemp)); + return resultTemp; + } + + private boolean isStringNode(ExprNode node) { + if (node == null) return false; + if (node.value instanceof String) return true; + if (node instanceof BinaryOpNode && "+".equals(((BinaryOpNode)node).op)) { + return isStringNode(((BinaryOpNode)node).left) || isStringNode(((BinaryOpNode)node).right); + } + return false; + } + + @Override + public String visit(UnaryNode node) { + System.err.println("DEBUG UnaryNode: op=" + node.op); + + // Get operand value + String operandTemp = dispatch(node.operand); + if (operandTemp == null) { + operandTemp = newTemp(); + System.err.println(" WARNING: operand returned null, using default"); + + // Try to extract value from ExprNode + if (node.operand instanceof ExprNode) { + ExprNode expr = (ExprNode) node.operand; + if (expr.value instanceof Integer) { + int val = (Integer) expr.value; + emit(new TACInstruction(Opcode.LOAD_IMM, operandTemp, val)); + } else if (expr.value instanceof Float) { + float val = (Float) expr.value; + emit(new TACInstruction(Opcode.LOAD_IMM, operandTemp, val)); + } else { + emit(new TACInstruction(Opcode.LOAD_IMM, operandTemp, 0)); + } + } else { + emit(new TACInstruction(Opcode.LOAD_IMM, operandTemp, 0)); + } + } + + String resultTemp = newTemp(); + + if ("-".equals(node.op)) { + // Check if we can load immediate negative value + if (node.operand instanceof ExprNode) { + ExprNode expr = (ExprNode) node.operand; + if (expr.value instanceof Integer) { + int val = (Integer) expr.value; + System.err.println(" Loading immediate negative: -" + val); + emit(new TACInstruction(Opcode.LOAD_IMM, resultTemp, -val)); + return resultTemp; + } else if (expr.value instanceof Float) { + float val = (Float) expr.value; + System.err.println(" Loading immediate negative: -" + val); + emit(new TACInstruction(Opcode.LOAD_IMM, resultTemp, -val)); + return resultTemp; + } + } + // General case: use NEG instruction + System.err.println(" Using NEG instruction"); + emit(new TACInstruction(Opcode.NEG, resultTemp, operandTemp)); + } else if ("!".equals(node.op)) { + // Logical NOT + String zeroTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, zeroTemp, 0)); + emit(new TACInstruction(Opcode.CMP_EQ, resultTemp, operandTemp, zeroTemp)); + } else { + // Unary plus or other + emit(new TACInstruction(Opcode.ASSIGN, resultTemp, operandTemp)); + } + + return resultTemp; + } + + @Override + public String visit(MethodCallNode node) { + // Push arguments + for (ExprNode arg : node.arguments) { + String t = dispatch(arg); + emit(new TACInstruction(Opcode.PARAM, t)); + } + + String result = newTemp(); + + // Check if it's a slot call + if (!node.slotNames.isEmpty()) { + // For slot calls, we need to handle multiple returns + emit(new TACInstruction(Opcode.CALL_SLOTS, result, node.qualifiedName, node.arguments.size())); + + // Extract slots if needed (for standalone slot calls) + for (int i = 0; i < node.slotNames.size(); i++) { + String slotName = node.slotNames.get(i); + String slotTemp = getOrAllocateVariable(slotName); + + if (i == 0) { + // First slot is primary return + emit(new TACInstruction(Opcode.ASSIGN, slotTemp, result)); + } else { + // Additional slots from array + String idxTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, idxTemp, i)); + emit(new TACInstruction(Opcode.LOAD_ARRAY, slotTemp, result, idxTemp)); + } + } + } else { + // Regular method call + emit(new TACInstruction(Opcode.CALL, result, node.qualifiedName, node.arguments.size())); + } + + return result; + } + + private String visitStatementExpression(ExprNode expr) { + if (expr instanceof MethodCallNode) { + MethodCallNode call = (MethodCallNode) expr; + // Visit but don't use the result + visit(call); + return null; + } else { + // For other expressions, just evaluate + return visit(expr); + } + } + + @Override + public String visit(ExprNode node) { + System.err.println("DEBUG ExprNode: name=" + node.name + ", value=" + node.value); + + if (node.name != null) { + // Variable reference + String varName = getOrAllocateVariable(node.name); + System.err.println(" -> Variable: " + node.name + " -> " + varName); + return varName; + } + + if (node.value != null) { + // Literal value + String temp = newTemp(); + if (node.value instanceof String) { + String str = (String) node.value; + // Remove quotes if present + if (str.startsWith("\"") && str.endsWith("\"")) { + str = str.substring(1, str.length() - 1); + } + System.err.println(" -> String literal: '" + str + "' -> " + temp); + emit(new TACInstruction(Opcode.LOAD_ADDR, temp, str)); + } else { + System.err.println(" -> Literal: " + node.value + " -> " + temp); + emit(new TACInstruction(Opcode.LOAD_IMM, temp, node.value)); + } + return temp; + } + + if (node.isNull) { + // null literal + String temp = newTemp(); + System.err.println(" -> null -> " + temp); + emit(new TACInstruction(Opcode.LOAD_IMM, temp, 0)); + return temp; + } + + // Empty expression - create default + String temp = newTemp(); + System.err.println(" WARNING: Empty ExprNode, using default 0 -> " + temp); + emit(new TACInstruction(Opcode.LOAD_IMM, temp, 0)); + return temp; + } + + @Override + public String visit(IndexAccessNode node) { + String arr = dispatch(node.array); + String idx = dispatch(node.index); + String res = newTemp(); + emit(new TACInstruction(Opcode.LOAD_ARRAY, res, arr, idx)); + return res; + } + + @Override + public String visit(ArrayNode node) { + String sizeTemp = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, sizeTemp, node.elements.size())); + String arrTemp = newTemp(); + emit(new TACInstruction(Opcode.ARRAY_NEW, arrTemp, sizeTemp)); + + // Store each element + for (int i = 0; i < node.elements.size(); i++) { + String val = dispatch(node.elements.get(i)); + String idx = newTemp(); + emit(new TACInstruction(Opcode.LOAD_IMM, idx, i)); + emit(new TACInstruction(Opcode.STORE_ARRAY, val, arrTemp, idx)); + } + return arrTemp; + } + + @Override + public String visit(TypeCastNode node) { + // For TAC, we'll just evaluate the expression + // Type checking happens at compile time or runtime + return visit(node.expression); + } + + @Override + public String visit(EqualityChainNode node) { + // Compile as series of comparisons + String left = dispatch(node.left); + String result = newTemp(); + String oneTemp = newTemp(); + String zeroTemp = newTemp(); + + emit(new TACInstruction(Opcode.LOAD_IMM, oneTemp, 1)); + emit(new TACInstruction(Opcode.LOAD_IMM, zeroTemp, 0)); + + if (node.isAllChain) { + // Initialize result to true (1) + emit(new TACInstruction(Opcode.ASSIGN, result, oneTemp)); + + for (ExprNode arg : node.chainArguments) { + String right = dispatch(arg); + String cmpTemp = newTemp(); + emit(new TACInstruction(mapOp(node.operator), cmpTemp, left, right)); + + // result = result AND cmpTemp + String andTemp = newTemp(); + emit(new TACInstruction(Opcode.CMP_NE, andTemp, cmpTemp, zeroTemp)); + emit(new TACInstruction(Opcode.ASSIGN, result, andTemp)); + } + } else { + // ANY chain: Initialize result to false (0) + emit(new TACInstruction(Opcode.ASSIGN, result, zeroTemp)); + + for (ExprNode arg : node.chainArguments) { + String right = dispatch(arg); + String cmpTemp = newTemp(); + emit(new TACInstruction(mapOp(node.operator), cmpTemp, left, right)); + + // result = result OR cmpTemp + String orTemp = newTemp(); + emit(new TACInstruction(Opcode.CMP_NE, orTemp, cmpTemp, zeroTemp)); + emit(new TACInstruction(Opcode.ASSIGN, result, orTemp)); + } + } + + return result; + } + + @Override + public String visit(BooleanChainNode node) { + // Compile ALL/ANY expressions + String result = newTemp(); + String oneTemp = newTemp(); + String zeroTemp = newTemp(); + + emit(new TACInstruction(Opcode.LOAD_IMM, oneTemp, 1)); + emit(new TACInstruction(Opcode.LOAD_IMM, zeroTemp, 0)); + + if (node.isAll) { + // ALL: Start with true, AND with each expression + emit(new TACInstruction(Opcode.ASSIGN, result, oneTemp)); + + for (ExprNode expr : node.expressions) { + String exprVal = dispatch(expr); + // Convert to boolean (0 or 1) + String boolTemp = newTemp(); + emit(new TACInstruction(Opcode.CMP_NE, boolTemp, exprVal, zeroTemp)); + + // result = result AND boolTemp + String andTemp = newTemp(); + emit(new TACInstruction(Opcode.CMP_NE, andTemp, result, zeroTemp)); + emit(new TACInstruction(Opcode.CMP_NE, andTemp, andTemp, zeroTemp)); + emit(new TACInstruction(Opcode.CMP_EQ, andTemp, andTemp, oneTemp)); + emit(new TACInstruction(Opcode.ASSIGN, result, andTemp)); + } + } else { + // ANY: Start with false, OR with each expression + emit(new TACInstruction(Opcode.ASSIGN, result, zeroTemp)); + + for (ExprNode expr : node.expressions) { + String exprVal = dispatch(expr); + // Convert to boolean (0 or 1) + String boolTemp = newTemp(); + emit(new TACInstruction(Opcode.CMP_NE, boolTemp, exprVal, zeroTemp)); + + // result = result OR boolTemp + String orTemp = newTemp(); + emit(new TACInstruction(Opcode.CMP_NE, orTemp, result, zeroTemp)); + emit(new TACInstruction(Opcode.CMP_NE, orTemp, orTemp, zeroTemp)); + emit(new TACInstruction(Opcode.CMP_EQ, orTemp, orTemp, oneTemp)); + emit(new TACInstruction(Opcode.ASSIGN, result, orTemp)); + } + } + + return result; + } + + private Opcode mapOp(String op) { + switch (op) { + case "+": return Opcode.ADD; + case "-": return Opcode.SUB; + case "*": return Opcode.MUL; + case "/": return Opcode.DIV; + case "%": return Opcode.MOD; + case "==": return Opcode.CMP_EQ; + case "!=": return Opcode.CMP_NE; + case "<": return Opcode.CMP_LT; + case "<=": return Opcode.CMP_LE; + case ">": return Opcode.CMP_GT; + case ">=": return Opcode.CMP_GE; + default: return Opcode.ADD; + } + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/TACInstruction.java b/src/main/java/cod/compiler/TACInstruction.java new file mode 100644 index 00000000..ca630c76 --- /dev/null +++ b/src/main/java/cod/compiler/TACInstruction.java @@ -0,0 +1,117 @@ +package cod.compiler; + +import java.util.*; + +public class TACInstruction { + public enum Opcode { + // Arithmetic + ADD, SUB, MUL, DIV, MOD, + // Logic / Comparison + CMP_EQ, CMP_NE, CMP_LT, CMP_LE, CMP_GT, CMP_GE, + NEG, INT_TO_STRING, + CONCAT, + // Data Movement + ASSIGN, LOAD_IMM, LOAD_ADDR, + // Control Flow + GOTO, IF_GOTO, LABEL, + RET, + // Object / Memory + LOAD_FIELD, STORE_FIELD, + LOAD_ARRAY, STORE_ARRAY, + ARRAY_NEW, + // Function Calls + CALL, CALL_SLOTS, PARAM, + // Runtime / IO + PRINT, READ_INPUT + } + + public final Opcode opcode; + public final String result; + public final Object operand1; + public final Object operand2; + + public TACInstruction(Opcode opcode, String result, Object operand1, Object operand2) { + this.opcode = opcode; + this.result = result; + this.operand1 = operand1; + this.operand2 = operand2; + } + + public TACInstruction(Opcode opcode, String result, Object operand1) { + this(opcode, result, operand1, null); + } + + public TACInstruction(Opcode opcode, Object operand1) { + this(opcode, null, operand1, null); + } + + public TACInstruction(Opcode opcode) { + this(opcode, null, null, null); + } + + @Override + public String toString() { + String s = String.format("%-12s", opcode); + if (result != null) s += " " + result + " ="; + if (operand1 != null) s += " " + operand1; + if (operand2 != null) s += ", " + operand2; + return s; + } + + // --- Analysis Helpers --- + + public String getDef() { + if (result == null) return null; + switch (opcode) { + case ADD: case SUB: case MUL: case DIV: case MOD: + case CMP_EQ: case CMP_NE: case CMP_LT: case CMP_LE: case CMP_GT: case CMP_GE: + case NEG: case INT_TO_STRING: case CONCAT: + case ASSIGN: case LOAD_IMM: case LOAD_ADDR: + case LOAD_FIELD: case LOAD_ARRAY: + case CALL: case CALL_SLOTS: + case READ_INPUT: case ARRAY_NEW: + return result; + default: + return null; + } + } + + public List getUses() { + List uses = new ArrayList(); + addUseIfVariable(uses, operand1); + addUseIfVariable(uses, operand2); + + // STORE operations read the 'result' field (it holds the value to store) + if (opcode == Opcode.STORE_ARRAY || opcode == Opcode.STORE_FIELD) { + if (result != null && isVariable(result)) { + uses.add(result); + } + } + + // IF_GOTO uses its operand1 (condition) + if (opcode == Opcode.IF_GOTO) { + // IF_GOTO cond, zero, label -> cond is used + addUseIfVariable(uses, result); // Sometimes cond is in result pos in constructor + } + + return uses; + } + + private void addUseIfVariable(List uses, Object operand) { + if (operand instanceof String) { + String str = (String) operand; + if (isVariable(str)) { + uses.add(str); + } + } + } + + private boolean isVariable(String s) { + if (s == null) return false; + // Exclude string literals and labels + if (s.startsWith("\"")) return false; + if (s.startsWith("L_") || s.startsWith("loop_") || s.startsWith("else_") || s.startsWith("endif_")) return false; + // Variables start with $ or letters + return true; + } +} \ No newline at end of file diff --git a/src/main/java/cod/compiler/TACProgram.java b/src/main/java/cod/compiler/TACProgram.java new file mode 100644 index 00000000..90ec51c3 --- /dev/null +++ b/src/main/java/cod/compiler/TACProgram.java @@ -0,0 +1,39 @@ +package cod.compiler; + +import java.util.*; + +public class TACProgram { + private Map> methods = new HashMap>(); + private Map nativeMethods = new HashMap(); + + public void addMethod(String name, List code) { + methods.put(name, new ArrayList(code)); + } + + public void addNativeMethod(String name, String assemblyCode) { + nativeMethods.put(name, assemblyCode); + } + + public List getMethod(String name) { + return methods.get(name); + } + + public Map> getMethods() { + return methods; + } + + public Map getNativeMethods() { + return nativeMethods; + } + + public void disassemble() { + System.out.println("=== MTOT Three-Address Code Disassembly ==="); + for (Map.Entry> entry : methods.entrySet()) { + System.out.println("\nMethod: " + entry.getKey()); + List instructions = entry.getValue(); + for (int i = 0; i < instructions.size(); i++) { + System.out.printf(" %04d: %s%n", i, instructions.get(i).toString()); + } + } + } +} \ No newline at end of file From 175224a3415a00e7608dad2c6217364071cfb447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:27:20 +0800 Subject: [PATCH 33/54] Add files via upload --- src/main/java/cod/debug/DebugSystem.java | 56 ++++---- src/main/java/cod/debug/Linter.java | 168 ++++++++++++++--------- 2 files changed, 131 insertions(+), 93 deletions(-) diff --git a/src/main/java/cod/debug/DebugSystem.java b/src/main/java/cod/debug/DebugSystem.java index 92a6a8a6..96db85da 100644 --- a/src/main/java/cod/debug/DebugSystem.java +++ b/src/main/java/cod/debug/DebugSystem.java @@ -2,8 +2,8 @@ package cod.debug; import java.util.*; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; +import java.text.SimpleDateFormat; +import java.util.Date; public class DebugSystem { public enum Level { @@ -26,20 +26,19 @@ public int getLevel() { } private static Level currentLevel = Level.INFO; - private static Set enabledCategories = new HashSet<>(); + private static Set enabledCategories = new HashSet(); private static boolean showTimestamp = true; private static boolean showThread = false; - private static Map timers = new HashMap<>(); + private static Map timers = new HashMap(); + private static SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); static { - // Enable common categories by default enabledCategories.add("AST"); enabledCategories.add("METHODS"); enabledCategories.add("SLOTS"); enabledCategories.add("INTERPRETER"); } - // Configuration methods public static void setLevel(Level level) { currentLevel = level; } @@ -53,15 +52,13 @@ public static void disableCategory(String category) { } public static void enableAllCategories() { - enabledCategories.addAll( - Arrays.asList( - "AST", - "METHODS", - "SLOTS", - "FIELDS", - "EXPRESSIONS", - "INTERPRETER", - "MEMORY")); + enabledCategories.add("AST"); + enabledCategories.add("METHODS"); + enabledCategories.add("SLOTS"); + enabledCategories.add("FIELDS"); + enabledCategories.add("EXPRESSIONS"); + enabledCategories.add("INTERPRETER"); + enabledCategories.add("MEMORY"); } public static void setShowTimestamp(boolean show) { @@ -72,7 +69,6 @@ public static void setShowThread(boolean show) { showThread = show; } - // Logging methods public static void error(String category, String message) { log(Level.ERROR, category, message); } @@ -93,7 +89,6 @@ public static void trace(String category, String message) { log(Level.TRACE, category, message); } - // Specialized logging methods public static void methodEntry(String methodName, Map params) { if (shouldLog(Level.DEBUG, "METHODS")) { debug("METHODS", "→ " + methodName + "(" + params + ")"); @@ -118,7 +113,6 @@ public static void fieldUpdate(String fieldName, Object value) { } } - // Performance timing public static void startTimer(String name) { if (shouldLog(Level.DEBUG, "PERF")) { timers.put(name, System.currentTimeMillis()); @@ -135,7 +129,14 @@ public static void stopTimer(String name) { } } - // AST building helpers + public static long getTimerDuration(String name) { + Long start = timers.get(name); + if (start != null) { + return System.currentTimeMillis() - start; + } + return -1; + } + public static void astBuilding(String nodeType, String details) { if (shouldLog(Level.TRACE, "AST")) { trace("AST", "Building " + nodeType + ": " + details); @@ -148,27 +149,24 @@ public static void astComplete(String nodeType, String summary) { } } - // Private implementation private static void log(Level level, String category, String message) { if (shouldLog(level, category)) { StringBuilder logLine = new StringBuilder(); - // Timestamp if (showTimestamp) { logLine.append("[") - .append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS"))) + .append(timeFormat.format(new Date())) .append("] "); } - // Level logLine.append("[").append(level).append("] "); - // Thread (optional) if (showThread) { - logLine.append("[").append(Thread.currentThread().getName()).append("] "); + logLine.append("[") + .append(Thread.currentThread().getName()) + .append("] "); } - // Category and message logLine.append(category).append(": ").append(message); System.out.println(logLine.toString()); @@ -178,4 +176,8 @@ private static void log(Level level, String category, String message) { private static boolean shouldLog(Level level, String category) { return level.getLevel() <= currentLevel.getLevel() && enabledCategories.contains(category); } -} + + public static Level getLevel() { + return currentLevel; + } +} \ No newline at end of file diff --git a/src/main/java/cod/debug/Linter.java b/src/main/java/cod/debug/Linter.java index 9e51fe27..3cf75f2b 100644 --- a/src/main/java/cod/debug/Linter.java +++ b/src/main/java/cod/debug/Linter.java @@ -1,6 +1,6 @@ package cod.debug; -import cod.ast.NamingValidator; +import cod.semantic.NamingValidator; import cod.ast.nodes.*; import java.util.ArrayList; import java.util.HashMap; @@ -19,6 +19,7 @@ public class Linter { private final List warnings; + private boolean completed; // --- State for Type-level checks --- private Set definedMethods; @@ -31,6 +32,7 @@ public class Linter { public Linter() { this.warnings = new ArrayList(); + this.completed = false; } /** @@ -40,39 +42,73 @@ public Linter() { */ public List lint(ProgramNode program) { warnings.clear(); - if (program.unit != null) { - visitUnit(program.unit); + completed = false; + + try { + if (program.unit != null) { + visitUnit(program.unit); + } + completed = true; + } catch (Exception e) { + System.err.println("Linting failed with error: " + e.getMessage()); + e.printStackTrace(); + completed = false; } + return warnings; } - - private void checkNamingConventions(TypeNode type) { - // Check type name - if (!NamingValidator.isPascalCase(type.name)) { - addWarning(type.name, "TYPE", "Type name '" + type.name + "' should use PascalCase"); + + /** + * Checks if the linting process completed successfully + * @return true if linting completed, false otherwise + */ + public boolean isCompleted() { + return completed; } - - // Check method names - for (MethodNode method : type.methods) { - if (!NamingValidator.startsWithLowerCase(method.name)) { - addWarning(type.name, method.name, "Method '" + method.name + "' should start with lowercase letter"); - } + + /** + * Gets the number of warnings found during linting + * @return number of warnings + */ + public int getWarningCount() { + return warnings.size(); } - - // Check field names - for (FieldNode field : type.fields) { - if (NamingValidator.isPascalCase(field.name)) { - addWarning(type.name, "FIELD", "Field '" + field.name + "' should not use PascalCase (reserved for classes)"); + + private void checkNamingConventions(TypeNode type) { + // --- FIX: Skip PascalCase check for synthetic types --- + if (type.name.equals("__MethodScript__") || + type.name.equals("__Script__") || + (type.name.startsWith("__") && type.name.endsWith("__"))) { + // Skip PascalCase check for synthetic/internal types + return; } - } - - // Check for ALL_CAPS fields that aren't actually constants - for (FieldNode field : type.fields) { - if (NamingValidator.isAllCaps(field.name) && field.value == null) { - addWarning(type.name, "FIELD", "Field '" + field.name + "' uses ALL_CAPS but has no initial value - is this meant to be a constant?"); + + // Check type name + if (!NamingValidator.isPascalCase(type.name)) { + addWarning(type.name, "TYPE", "Type name '" + type.name + "' should use PascalCase"); + } + + // Check method names + for (MethodNode method : type.methods) { + if (!NamingValidator.startsWithLowerCase(method.name)) { + addWarning(type.name, method.name, "Method '" + method.name + "' should start with lowercase letter"); + } + } + + // Check field names + for (FieldNode field : type.fields) { + if (NamingValidator.isPascalCase(field.name)) { + addWarning(type.name, "FIELD", "Field '" + field.name + "' should not use PascalCase (reserved for classes)"); + } + } + + // Check for ALL_CAPS fields that aren't actually constants + for (FieldNode field : type.fields) { + if (NamingValidator.isAllCaps(field.name) && field.value == null) { + addWarning(type.name, "FIELD", "Field '" + field.name + "' uses ALL_CAPS but has no initial value - is this meant to be a constant?"); + } } } -} private void visitUnit(UnitNode unit) { for (TypeNode type : unit.types) { @@ -81,44 +117,44 @@ private void visitUnit(UnitNode unit) { } private void visitType(TypeNode type) { - // Initialize sets for this type - this.definedMethods = new HashSet(); - this.calledMethods = new HashSet(); - this.methodMap = new HashMap(); - - // ADD THIS LINE: Check naming conventions - checkNamingConventions(type); - - // First pass: Find all defined methods in this type - for (MethodNode method : type.methods) { - definedMethods.add(method.name); - methodMap.put(method.name, method); - } - - // "main" is a special entry point, so it's always considered "used" - if (definedMethods.contains("main")) { - calledMethods.add("main"); - } + // Initialize sets for this type + this.definedMethods = new HashSet(); + this.calledMethods = new HashSet(); + this.methodMap = new HashMap(); + + // Check naming conventions + checkNamingConventions(type); + + // First pass: Find all defined methods in this type + for (MethodNode method : type.methods) { + definedMethods.add(method.name); + methodMap.put(method.name, method); + } + + // "main" is a special entry point, so it's always considered "used" + if (definedMethods.contains("main")) { + calledMethods.add("main"); + } - // Second pass: Visit all methods to find calls and analyze bodies - for (MethodNode method : type.methods) { - visitMethod(method, type.name); - } + // Second pass: Visit all methods to find calls and analyze bodies + for (MethodNode method : type.methods) { + visitMethod(method, type.name); + } - // Third pass: Analyze the results for this type - for (String methodName : definedMethods) { - if (!calledMethods.contains(methodName)) { - MethodNode method = methodMap.get(methodName); - if ("local".equals(method.visibility)) { - addWarning( - type.name, - methodName, - "Method '" + methodName + "' is 'local' and is never called." - ); + // Third pass: Analyze the results for this type + for (String methodName : definedMethods) { + if (!calledMethods.contains(methodName)) { + MethodNode method = methodMap.get(methodName); + if ("local".equals(method.visibility)) { + addWarning( + type.name, + methodName, + "Method '" + methodName + "' is 'local' and is never called." + ); + } } } } -} private void visitMethod(MethodNode method, String typeName) { // Initialize sets for this method @@ -137,7 +173,7 @@ private void visitMethod(MethodNode method, String typeName) { } // Visit all statements in the method body - for (StatementNode stmt : method.body) { + for (StmtNode stmt : method.body) { visitStatement(stmt); } @@ -166,7 +202,7 @@ private void visitMethod(MethodNode method, String typeName) { // --- Statement Visitor --- - private void visitStatement(StatementNode stmt) { + private void visitStatement(StmtNode stmt) { if (stmt == null) { return; } @@ -208,13 +244,13 @@ private void visitStatement(StatementNode stmt) { visitExpression(arg); } - } else if (stmt instanceof IfNode) { - IfNode ifNode = (IfNode) stmt; + } else if (stmt instanceof StmtIfNode) { + StmtIfNode ifNode = (StmtIfNode) stmt; visitExpression(ifNode.condition); - for (StatementNode s : ifNode.thenBlock.statements) { + for (StmtNode s : ifNode.thenBlock.statements) { visitStatement(s); } - for (StatementNode s : ifNode.elseBlock.statements) { + for (StmtNode s : ifNode.elseBlock.statements) { visitStatement(s); } @@ -230,7 +266,7 @@ private void visitStatement(StatementNode stmt) { visitExpression(forNode.range.step); // Body statements are visited - for (StatementNode s : forNode.body.statements) { + for (StmtNode s : forNode.body.statements) { visitStatement(s); } From dc31eadb9a7b1ece5a1c4dbb6a530b94af095132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:28:12 +0800 Subject: [PATCH 34/54] Add files via upload --- .../cod/interpreter/ExecutionContext.java | 35 + src/main/java/cod/interpreter/IOHandler.java | 116 ++- .../java/cod/interpreter/Interpreter.java | 597 +++++++---- .../cod/interpreter/InterpreterVisitor.java | 933 ++++++++++++++++++ .../java/cod/interpreter/NaturalArray.java | 627 ++++++++++++ .../java/cod/interpreter/ObjectInstance.java | 2 +- src/main/java/cod/interpreter/TypeSystem.java | 455 ++++++--- src/main/java/cod/interpreter/TypedValue.java | 26 + 8 files changed, 2415 insertions(+), 376 deletions(-) create mode 100644 src/main/java/cod/interpreter/ExecutionContext.java create mode 100644 src/main/java/cod/interpreter/InterpreterVisitor.java create mode 100644 src/main/java/cod/interpreter/NaturalArray.java create mode 100644 src/main/java/cod/interpreter/TypedValue.java diff --git a/src/main/java/cod/interpreter/ExecutionContext.java b/src/main/java/cod/interpreter/ExecutionContext.java new file mode 100644 index 00000000..f84a20bf --- /dev/null +++ b/src/main/java/cod/interpreter/ExecutionContext.java @@ -0,0 +1,35 @@ +package cod.interpreter; + +import java.util.Map; +import java.util.Set; +import java.util.HashMap; +import java.util.HashSet; + +public class ExecutionContext { + public ObjectInstance objectInstance; + public Map locals; + public Map slotValues; + public Map slotTypes; + // NEW: Map to track the explicit type declared for local variables + public Map localTypes; + public Set slotsInCurrentPath; + + public ExecutionContext(ObjectInstance objectInstance, + Map locals, + Map slotValues, + Map slotTypes) { + this.objectInstance = objectInstance; + this.locals = locals; + this.slotValues = slotValues; + this.slotTypes = slotTypes; + + // Initialize the NEW map + this.localTypes = new HashMap(); + + this.slotsInCurrentPath = new HashSet(); + + if (slotValues != null && !slotValues.isEmpty()) { + this.slotsInCurrentPath.addAll(slotValues.keySet()); + } + } +} \ No newline at end of file diff --git a/src/main/java/cod/interpreter/IOHandler.java b/src/main/java/cod/interpreter/IOHandler.java index 314cbc7e..aedb8105 100644 --- a/src/main/java/cod/interpreter/IOHandler.java +++ b/src/main/java/cod/interpreter/IOHandler.java @@ -1,6 +1,8 @@ package cod.interpreter; import cod.debug.DebugSystem; +import cod.syntax.Keyword; +import java.math.BigDecimal; import java.util.Scanner; public class IOHandler { @@ -10,50 +12,57 @@ public Object readInput(String targetType) { DebugSystem.debug("INPUT", "Reading input as type: " + targetType); try { - System.out.print(">> "); System.out.flush(); - switch (targetType) { - case "int": - // For int, read the entire line and parse it - String intLine = inputScanner.nextLine().trim(); - if (intLine.isEmpty()) { - intLine = inputScanner.nextLine().trim(); // Try again if empty - } - return Integer.parseInt(intLine); + // Convert to Keyword for safe comparison + Keyword targetKeyword; + try { + targetKeyword = Keyword.valueOf(targetType.toUpperCase()); + } catch (IllegalArgumentException e) { + targetKeyword = null; // Unknown type + } + + if (targetKeyword == Keyword.INT) { + // For int, read the entire line and parse it + String intLine = inputScanner.nextLine().trim(); + if (intLine.isEmpty()) { + intLine = inputScanner.nextLine().trim(); // Try again if empty + } + return Integer.parseInt(intLine); - case "float": - // For float, read the entire line and parse it - String floatLine = inputScanner.nextLine().trim(); - if (floatLine.isEmpty()) { - floatLine = inputScanner.nextLine().trim(); - } - return Float.parseFloat(floatLine); + } else if (targetKeyword == Keyword.FLOAT) { + // For float, read the entire line and parse it + String floatLine = inputScanner.nextLine().trim(); + if (floatLine.isEmpty()) { + floatLine = inputScanner.nextLine().trim(); + } + return Float.parseFloat(floatLine); - case "string": - // For string, just read the line - String stringValue = inputScanner.nextLine().trim(); - if (stringValue.isEmpty()) { - stringValue = inputScanner.nextLine().trim(); - } - return stringValue; + } else if (targetKeyword == Keyword.TEXT) { // ← CHANGED FROM STRING TO TEXT + // For text, just read the line + String textValue = inputScanner.nextLine().trim(); + if (textValue.isEmpty()) { + textValue = inputScanner.nextLine().trim(); + } + return textValue; - case "bool": - // For bool, read the line and check content - String boolLine = inputScanner.nextLine().trim().toLowerCase(); - if (boolLine.isEmpty()) { - boolLine = inputScanner.nextLine().trim().toLowerCase(); - } - return boolLine.equals("true") - || boolLine.equals("1") - || boolLine.equals("yes"); + } else if (targetKeyword == Keyword.BOOL) { + // For bool, read the line and check content + String boolLine = inputScanner.nextLine().trim().toLowerCase(); + if (boolLine.isEmpty()) { + boolLine = inputScanner.nextLine().trim().toLowerCase(); + } + return boolLine.equals("true") + || boolLine.equals("1") + || boolLine.equals("yes"); - default: - String defaultLine = inputScanner.nextLine().trim(); - if (defaultLine.isEmpty()) { - defaultLine = inputScanner.nextLine().trim(); - } - return defaultLine; + } else { + // Unknown type, read as string + String defaultLine = inputScanner.nextLine().trim(); + if (defaultLine.isEmpty()) { + defaultLine = inputScanner.nextLine().trim(); + } + return defaultLine; } } catch (Exception e) { DebugSystem.error( @@ -67,10 +76,37 @@ public Object readInput(String targetType) { } public void output(Object value) { - System.out.print(String.valueOf(value)); // CHANGED: println to print + // Format large numbers without scientific notation + String output; + + // FIX: Handle BigDecimal directly + if (value instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) value; + bd = bd.stripTrailingZeros(); // Remove .000 + output = bd.toPlainString(); // No scientific notation + } else if (value instanceof Double) { + double d = (Double) value; + // If it's a whole number and reasonably sized, show as integer + if (d == Math.floor(d) && d <= 1e15 && d >= -1e15) { + output = String.format("%.0f", d); + } else { + output = String.valueOf(value); + } + } else if (value instanceof Float) { + float f = (Float) value; + if (f == Math.floor(f) && f <= 1e15 && f >= -1e15) { + output = String.format("%.0f", (double) f); + } else { + output = String.valueOf(value); + } + } else { + output = String.valueOf(value); } + + System.out.print(output); +} public void close() { inputScanner.close(); } -} \ No newline at end of file +} diff --git a/src/main/java/cod/interpreter/Interpreter.java b/src/main/java/cod/interpreter/Interpreter.java index 2cd5d3ad..b7ce29f2 100644 --- a/src/main/java/cod/interpreter/Interpreter.java +++ b/src/main/java/cod/interpreter/Interpreter.java @@ -1,265 +1,440 @@ package cod.interpreter; +import cod.syntax.Keyword; +import static cod.syntax.Keyword.*; import cod.ast.nodes.*; -import cod.ast.ImportResolver; +import cod.semantic.ImportResolver; import cod.debug.DebugSystem; -import java.util.*; -import java.io.File; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; public class Interpreter { - Map currentSlots = null; - Map currentSlotTypes = null; // NEW: Track slot types for validation - Set slotsInCurrentPath = new HashSet<>(); - - private IOHandler ioHandler = new IOHandler(); - private ImportResolver importResolver = new ImportResolver(); - private TypeSystem typeSystem = new TypeSystem(); - private ExpressionEvaluator exprEvaluator; - private StatementEvaluator stmtEvaluator; - - public Interpreter() { - this.exprEvaluator = new ExpressionEvaluator(typeSystem, this); - this.stmtEvaluator = new StatementEvaluator(this, exprEvaluator, ioHandler, typeSystem); - } + private IOHandler ioHandler = new IOHandler(); + private ImportResolver importResolver = new ImportResolver(); + private TypeSystem typeSystem = new TypeSystem(); + private InterpreterVisitor visitor; - private Map emptyParamMap() { - return Collections.emptyMap(); - } + public Interpreter() { + this.visitor = new InterpreterVisitor(this, typeSystem, ioHandler); + } - public ImportResolver getImportResolver() { - return importResolver; - } + public ImportResolver getImportResolver() { + return importResolver; + } - public ExpressionEvaluator getExpressionEvaluator() { - return exprEvaluator; + boolean shouldReturnEarly(Map slotValues, Set slotsInCurrentPath) { + if (slotsInCurrentPath.isEmpty()) return false; + for (String slotName : slotsInCurrentPath) { + if (slotValues.get(slotName) == null) return false; } - - public StatementEvaluator getStatementEvaluator() { - return stmtEvaluator; + return true; + } + + public Object evalReplStatement( + StmtNode stmt, + ObjectInstance obj, + Map locals, + Map slotValues) { + Map slotTypes = new HashMap(); + ExecutionContext ctx = new ExecutionContext(obj, locals, slotValues, slotTypes); + visitor.pushContext(ctx); + try { + return visitor.visit((ASTNode) stmt); + } finally { + visitor.popContext(); + } + } + + public void run(ProgramNode program) { + DebugSystem.startTimer("program_execution"); + DebugSystem.info("INTERPRETER", "Starting program execution"); + + // Handle different program types + if (program.programType == null) { + // Fallback to original behavior (assume module) + DebugSystem.warn("INTERPRETER", "No program type detected, assuming MODULE"); + runModule(program); + } else { + switch (program.programType) { + case MODULE: + runModule(program); + break; + case SCRIPT: + runScript(program); + break; + case METHOD_SCRIPT: + runMethodScript(program); + break; + default: + throw new RuntimeException("Unknown program type: " + program.programType); + } } - public void run(ProgramNode program) { - DebugSystem.startTimer("program_execution"); - DebugSystem.info("INTERPRETER", "Starting program execution"); - - UnitNode unit = program.unit; - DebugSystem.debug("INTERPRETER", "Processing unit: " + unit.name); - - initializeImportResolver(unit); - - for (TypeNode type : unit.types) { - DebugSystem.debug("INTERPRETER", "Processing type: " + type.name); - - for (MethodNode method : type.methods) { - boolean isMainMethod = "main".equals(method.name); - boolean hasNoParameters = method.parameters.isEmpty(); - - if (isMainMethod && hasNoParameters) { - DebugSystem.methodEntry("main", emptyParamMap()); - - ObjectInstance obj = new ObjectInstance(type); - if (type.constructor != null) { - evalConstructor(type.constructor, obj); - } - - Object result = evalMethod(method, obj, new HashMap()); - DebugSystem.methodExit("main", result); - - } else if (isMainMethod && !hasNoParameters) { - DebugSystem.warn("INTERPRETER", "Ignoring main() with parameters: " + method.parameters); - } - } + DebugSystem.stopTimer("program_execution"); + DebugSystem.info("INTERPRETER", "Program execution completed"); + ioHandler.close(); + } + + /** + * Run a MODULE program. Must have unit declaration and classes. Executes main() method in a + * class. + */ + private void runModule(ProgramNode program) { + UnitNode unit = program.unit; + initializeImportResolver(unit); + + // Find and execute main() method in a class + boolean mainExecuted = false; + for (TypeNode type : unit.types) { + for (MethodNode method : type.methods) { + boolean isMainMethod = "main".equals(method.name); + boolean hasNoParameters = method.parameters.isEmpty(); + + if (isMainMethod && hasNoParameters) { + DebugSystem.methodEntry("main", Collections.emptyMap()); + ObjectInstance obj = new ObjectInstance(type); + initializeFields(type, obj); + if (type.constructor != null) evalConstructor(type.constructor, obj); + Object result = evalMethod(method, obj, new HashMap()); + DebugSystem.methodExit("main", result); + mainExecuted = true; + break; // Only execute first main() found + } else if (isMainMethod && !hasNoParameters) { + DebugSystem.warn("INTERPRETER", "Ignoring main() with parameters in class: " + type.name); } - - DebugSystem.stopTimer("program_execution"); - DebugSystem.info("INTERPRETER", "Program execution completed"); - ioHandler.close(); + } + if (mainExecuted) break; } - private void initializeImportResolver(UnitNode unit) { - if (unit.resolvedImports != null && !unit.resolvedImports.isEmpty()) { - for (Map.Entry entry : unit.resolvedImports.entrySet()) { - importResolver.preloadImport(entry.getKey(), entry.getValue()); - } - } - if (unit.imports != null && !unit.imports.imports.isEmpty()) { - for (String importName : unit.imports.imports) { - importResolver.registerImport(importName); + if (!mainExecuted) { + throw new RuntimeException("Module must have a class with 'main()' method"); + } + } + + /** Run a SCRIPT program. Direct statements executed top-down. No classes, no methods required. */ + private void runScript(ProgramNode program) { + UnitNode unit = program.unit; + initializeImportResolver(unit); + + // Create a dummy object instance for script execution + ObjectInstance obj = new ObjectInstance(null); + Map locals = new HashMap(); + + DebugSystem.methodEntry("script", Collections.emptyMap()); + + // Execute all statements in order (script has only synthetic __Script__ type) + for (TypeNode type : unit.types) { + // Look for synthetic script type + if (type.name != null && type.name.equals("__Script__")) { + if (type.statements != null) { + for (StmtNode stmt : type.statements) { + ExecutionContext ctx = new ExecutionContext(obj, locals, null, null); + visitor.pushContext(ctx); + try { + Object result = visitor.visit((ASTNode) stmt); + DebugSystem.debug("SCRIPT", "Executed statement: " + stmt.getClass().getSimpleName()); + if (result != null) { + DebugSystem.debug("SCRIPT", " Result: " + result); + } + } finally { + visitor.popContext(); } + } } + break; + } } - private void evalConstructor(ConstructorNode constructor, ObjectInstance obj) { - DebugSystem.methodEntry(constructor.getClass().getSimpleName(), emptyParamMap()); - - Map locals = new HashMap(); - for (ParamNode p : constructor.parameters) { - locals.put(p.name, 0); - } - - for (StatementNode stmt : constructor.body) { - Object val = stmtEvaluator.evalStmt(stmt, obj, locals, null); - if (stmt instanceof FieldNode) { - FieldNode field = (FieldNode) stmt; - obj.fields.put(field.name, val); + DebugSystem.methodExit("script", "completed"); + } + + /** Run a METHOD_SCRIPT program. Only methods, no direct code. Must have main() method. */ + private void runMethodScript(ProgramNode program) { + UnitNode unit = program.unit; + initializeImportResolver(unit); + + // Find main() method in synthetic __MethodScript__ type + MethodNode mainMethod = null; + TypeNode containerType = null; + + for (TypeNode type : unit.types) { + // Look for synthetic method script type + if (type.name != null && type.name.equals("__MethodScript__")) { + containerType = type; + if (type.methods != null) { + for (MethodNode method : type.methods) { + if ("main".equals(method.name) + && (method.parameters == null || method.parameters.isEmpty())) { + mainMethod = method; + break; } + } } - - DebugSystem.methodExit(constructor.getClass().getSimpleName(), "constructor completed"); + break; + } } - private Object evalMethod(MethodNode method, ObjectInstance obj, Map locals) { - DebugSystem.methodEntry(method.name, locals); - - // Initialize slot values and types - Map slotValues = new HashMap(); - Map slotTypes = new HashMap(); - - for (SlotNode s : method.returnSlots) { - slotValues.put(s.name, null); - slotTypes.put(s.name, s.type); // Store type for validation - DebugSystem.debug("SLOTS", "Initialized slot: " + s.name + " (Type: " + s.type + ") = null"); - } - - // Push context - Map previousSlots = currentSlots; - Map previousSlotTypes = currentSlotTypes; - currentSlots = slotValues; - currentSlotTypes = slotTypes; - - slotsInCurrentPath.clear(); - boolean hasSlots = !method.returnSlots.isEmpty(); - if (hasSlots) { - slotsInCurrentPath.addAll(slotValues.keySet()); - } - - Object result = null; - - // Process statements - for (int i = 0; i < method.body.size(); i++) { - StatementNode stmt = method.body.get(i); - result = stmtEvaluator.evalStmt(stmt, obj, locals, slotValues); - - if (hasSlots && shouldReturnEarly(slotValues)) { - DebugSystem.debug("SLOTS", "Early return triggered - all slots assigned in current path"); - break; + // If not found in synthetic type, look in any type + if (mainMethod == null) { + for (TypeNode type : unit.types) { + if (type.methods != null) { + for (MethodNode method : type.methods) { + if ("main".equals(method.name) + && (method.parameters == null || method.parameters.isEmpty())) { + mainMethod = method; + containerType = type; + break; } + } } + if (mainMethod != null) break; + } + } - // Pop context - currentSlots = previousSlots; - currentSlotTypes = previousSlotTypes; - - DebugSystem.methodExit(method.name, slotValues); - return result; // Usually null unless simple return + if (mainMethod == null) { + throw new RuntimeException("Method script requires a 'main()' method"); } - boolean shouldReturnEarly(Map slotValues) { - for (String slotName : slotsInCurrentPath) { - if (slotValues.get(slotName) == null) { - return false; - } + DebugSystem.methodEntry("main", Collections.emptyMap()); + ObjectInstance obj = new ObjectInstance(containerType); + initializeFields(containerType, obj); + if (containerType.constructor != null) { + evalConstructor(containerType.constructor, obj); + } + Object result = evalMethod(mainMethod, obj, new HashMap()); + DebugSystem.methodExit("main", result); + } + + private void initializeFields(TypeNode type, ObjectInstance obj) { + ExecutionContext ctx = new ExecutionContext(obj, new HashMap(), null, null); + visitor.pushContext(ctx); + try { + if (type.fields != null) { + for (FieldNode field : type.fields) { + visitor.visit((ASTNode) field); } - return true; + } + } finally { + visitor.popContext(); } + } - public Object evalMethodCall(MethodCallNode call, ObjectInstance obj, Map locals) { - MethodNode method = null; - - for (int i = 0; i < obj.type.methods.size(); i++) { - MethodNode candidate = obj.type.methods.get(i); - if (candidate.name.equals(call.name)) { - method = candidate; - break; - } + private void initializeImportResolver(UnitNode unit) { + if (unit.resolvedImports != null && !unit.resolvedImports.isEmpty()) { + for (Map.Entry entry : unit.resolvedImports.entrySet()) { + importResolver.preloadImport(entry.getKey(), entry.getValue()); + } + } + if (unit.imports != null && !unit.imports.imports.isEmpty()) { + for (String importName : unit.imports.imports) { + importResolver.registerImport(importName); + } + } + } + + private void evalConstructor(ConstructorNode constructor, ObjectInstance obj) { + DebugSystem.methodEntry("Constructor", Collections.emptyMap()); + Map locals = new HashMap(); + for (ParamNode p : constructor.parameters) locals.put(p.name, 0); + ExecutionContext ctx = new ExecutionContext(obj, locals, null, null); + visitor.pushContext(ctx); + for (StmtNode stmt : constructor.body) { + Object val = visitor.visit((ASTNode) stmt); + if (stmt instanceof FieldNode) obj.fields.put(((FieldNode) stmt).name, val); + } + visitor.popContext(); + DebugSystem.methodExit("Constructor", "completed"); + } + + private Object evalMethod(MethodNode method, ObjectInstance obj, Map locals) { + DebugSystem.methodEntry(method.name, locals); + // Use LinkedHashMap to preserve slot order + Map slotValues = new LinkedHashMap(); + Map slotTypes = new LinkedHashMap(); + if (method.returnSlots != null) { + for (SlotNode s : method.returnSlots) { + slotValues.put(s.name, null); + slotTypes.put(s.name, s.type); + } + } + ExecutionContext ctx = new ExecutionContext(obj, locals, slotValues, slotTypes); + visitor.pushContext(ctx); + Object result = null; + boolean hasSlots = method.returnSlots != null && !method.returnSlots.isEmpty(); + + try { + if (method.body != null) { + for (StmtNode stmt : method.body) { + result = visitor.visit((ASTNode) stmt); + if (hasSlots && shouldReturnEarly(slotValues, ctx.slotsInCurrentPath)) break; } - - if (method == null) { - String qualifiedMethodName = call.qualifiedName != null ? call.qualifiedName : call.name; - method = resolveImportedMethod(qualifiedMethodName); + } + } catch (EarlyExitException e) { + // Early exit requested + } + visitor.popContext(); + DebugSystem.methodExit(method.name, slotValues); + + // Return slot values if method has return slots, otherwise return result + return hasSlots ? slotValues : result; + } + + public Object evalMethodCall( + MethodCallNode call, ObjectInstance obj, Map locals) { + MethodNode method = null; + if (obj.type != null && obj.type.methods != null) { + for (MethodNode m : obj.type.methods) { + if (m.name.equals(call.name)) { + method = m; + break; } - - if (method == null) { - throw new RuntimeException("Method not found: " + (call.qualifiedName != null ? call.qualifiedName : call.name)); + } + } + if (method == null) { + String qName = call.qualifiedName != null ? call.qualifiedName : call.name; + method = resolveImportedMethod(qName); + } + if (method == null) throw new RuntimeException("Method not found: " + call.name); + if (method.isBuiltin) return handleBuiltinMethod(method, call); + + Map newLocals = new HashMap(); + Map newLocalTypes = new HashMap(); + + int argCount = call.arguments != null ? call.arguments.size() : 0; + int paramCount = method.parameters != null ? method.parameters.size() : 0; + + // Process each parameter + for (int i = 0; i < paramCount; i++) { + ParamNode param = method.parameters.get(i); + Object argValue = null; + + // Check if argument is provided + if (i < argCount) { + ExprNode argExpr = call.arguments.get(i); + + // Check if argument is underscore placeholder + if (argExpr instanceof ExprNode && "_".equals(((ExprNode) argExpr).name)) { + // Use underscore placeholder + if (param.hasDefaultValue) { + // Evaluate default value expression + argValue = visitor.visit((ASTNode) param.defaultValue); + } else { + throw new RuntimeException( + "Parameter '" + + param.name + + "' has no default value and cannot be skipped with '_'"); + } + } else { + // Regular argument + argValue = visitor.visit((ASTNode) argExpr); } - - if (method.isBuiltin) { - return handleBuiltinMethod(method, call, obj, locals); + } else { + if (param.hasDefaultValue) { + argValue = visitor.visit((ASTNode) param.defaultValue); + + // Validate type (even for defaults!) + if (!typeSystem.validateType(param.type, argValue)) { + throw new RuntimeException( + "Default value for parameter '" + + param.name + + "' returns wrong type. Expected " + + param.type + + ", got: " + + typeSystem.getConcreteType(argValue)); + } } + } - Map newLocals = new HashMap(); - if (call.arguments.size() != method.parameters.size()) { - throw new RuntimeException("Parameter count mismatch for method " + method.name); - } + String paramType = param.type; - for (int i = 0; i < call.arguments.size(); i++) { - ParamNode param = method.parameters.get(i); - Object argValue = exprEvaluator.evaluate(call.arguments.get(i), obj, locals); - newLocals.put(param.name, argValue); + // Type validation (existing code) + if (!typeSystem.validateType(paramType, argValue)) { + if (paramType.equals(Keyword.TEXT.toString())) { + argValue = typeSystem.convertType(argValue, paramType); + } else { + throw new RuntimeException( + "Argument type mismatch for parameter " + param.name + ". Expected " + paramType); } + } - // Initialize context for called method - Map slotValues = new HashMap(); - Map slotTypes = new HashMap(); - - for (SlotNode s : method.returnSlots) { - slotValues.put(s.name, null); - slotTypes.put(s.name, s.type); - } + if (paramType.contains("|")) { + String activeType = typeSystem.getConcreteType(typeSystem.unwrap(argValue)); + argValue = new TypedValue(argValue, activeType, paramType); + } - Map previousSlots = currentSlots; - Map previousSlotTypes = currentSlotTypes; - currentSlots = slotValues; - currentSlotTypes = slotTypes; + newLocals.put(param.name, argValue); + newLocalTypes.put(param.name, paramType); + } - Set previousSlotsInPath = slotsInCurrentPath; - boolean calledMethodHasSlots = !method.returnSlots.isEmpty(); - if (calledMethodHasSlots) { - slotsInCurrentPath = new HashSet<>(slotValues.keySet()); - } else { - slotsInCurrentPath = new HashSet<>(); - } + // Check for too many arguments + if (argCount > paramCount) { + throw new RuntimeException( + "Too many arguments: expected " + paramCount + ", got " + argCount); + } - for (StatementNode stmt : method.body) { - stmtEvaluator.evalStmt(stmt, obj, newLocals, slotValues); - if (calledMethodHasSlots && shouldReturnEarly(slotValues)) { - break; - } - } + // Rest of the method remains the same... + Map slotValues = new LinkedHashMap(); + Map slotTypes = new LinkedHashMap(); + if (method.returnSlots != null) { + for (SlotNode s : method.returnSlots) { + slotValues.put(s.name, null); + slotTypes.put(s.name, s.type); + } + } - currentSlots = previousSlots; - currentSlotTypes = previousSlotTypes; - slotsInCurrentPath = previousSlotsInPath; + ExecutionContext ctx = new ExecutionContext(obj, newLocals, slotValues, slotTypes); + ctx.localTypes.putAll(newLocalTypes); - return slotValues; - } + visitor.pushContext(ctx); + boolean calledMethodHasSlots = method.returnSlots != null && !method.returnSlots.isEmpty(); - private Object handleBuiltinMethod(MethodNode method, MethodCallNode call, ObjectInstance obj, Map locals) { - switch (method.name) { - case "outa": - return handleSysOuta(call, obj, locals); - default: - throw new RuntimeException("Unknown builtin method: " + method.name); + try { + if (method.body != null) { + for (StmtNode stmt : method.body) { + visitor.visit((ASTNode) stmt); + if (calledMethodHasSlots && shouldReturnEarly(slotValues, ctx.slotsInCurrentPath)) break; } + } + } catch (EarlyExitException e) { } - private Object handleSysOuta(MethodCallNode call, ObjectInstance obj, Map locals) { - StringBuilder result = new StringBuilder(); + visitor.popContext(); + + return calledMethodHasSlots ? slotValues : null; + } + + private Object handleBuiltinMethod(MethodNode method, MethodCallNode call) { + if ("printp".equals(method.name)) { + StringBuilder result = new StringBuilder(); + if (call.arguments != null) { for (int i = 0; i < call.arguments.size(); i++) { - Object value = exprEvaluator.evaluate(call.arguments.get(i), obj, locals); - result.append(String.valueOf(value)); + Object value = visitor.visit((ASTNode) call.arguments.get(i)); + result.append(String.valueOf(value)); } - ioHandler.output(result.toString()); - return null; + } + ioHandler.output(result.toString()); + return null; + } + throw new RuntimeException("Unknown builtin method: " + method.name); + } + + private MethodNode resolveImportedMethod(String qualifiedMethodName) { + try { + return importResolver.findMethod(qualifiedMethodName); + } catch (Exception e) { + e.printStackTrace(); + return null; } + } - private MethodNode resolveImportedMethod(String qualifiedMethodName) { - try { - return importResolver.findMethod(qualifiedMethodName); - } catch (Exception e) { - e.printStackTrace(); - return null; - } + public static class EarlyExitException extends RuntimeException { + public EarlyExitException() { + super("Early exit"); } -} \ No newline at end of file + } +} diff --git a/src/main/java/cod/interpreter/InterpreterVisitor.java b/src/main/java/cod/interpreter/InterpreterVisitor.java new file mode 100644 index 00000000..3298ec0a --- /dev/null +++ b/src/main/java/cod/interpreter/InterpreterVisitor.java @@ -0,0 +1,933 @@ +package cod.interpreter; + +import static cod.syntax.Keyword.*; +import cod.ast.ASTFactory; +import cod.ast.BaseASTVisitor; +import cod.ast.nodes.*; +import java.util.*; +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class InterpreterVisitor extends BaseASTVisitor { + + private final Interpreter interpreter; + public final TypeSystem typeSystem; + private final IOHandler ioHandler; + private final Stack contextStack = new Stack(); + + // Scale for BigDecimal operations (consistent with TypeSystem) + private static final int DECIMAL_SCALE = 20; + + public InterpreterVisitor(Interpreter interpreter, TypeSystem typeSystem, IOHandler ioHandler) { + this.interpreter = interpreter; + this.typeSystem = typeSystem; + this.ioHandler = ioHandler; + } + + public void pushContext(ExecutionContext context) { contextStack.push(context); } + public void popContext() { contextStack.pop(); } + public ExecutionContext getCurrentContext() { return contextStack.peek(); } + +@Override +public Object visit(ExprNode node) { + ExecutionContext ctx = getCurrentContext(); + + if (node.name != null) { + + if (ctx.locals.containsKey(node.name)) return ctx.locals.get(node.name); + if (ctx.slotValues != null && ctx.slotValues.containsKey(node.name)) return ctx.slotValues.get(node.name); + if (ctx.objectInstance.fields.containsKey(node.name)) return ctx.objectInstance.fields.get(node.name); + + throw new RuntimeException("Undefined Variable: " + node.name); + } + + if (node.value != null) { + if (node.value instanceof String) { + String s = (String) node.value; + if (s.startsWith("\"") && s.endsWith("\"") && s.length() >= 2) return s.substring(1, s.length() - 1); + return s; + } + + // FIX: Strip trailing zeros from BigDecimal literals + if (node.value instanceof BigDecimal) { + return ((BigDecimal) node.value).stripTrailingZeros(); + } + + return node.value; + } + + return null; +} + + @Override +public Object visit(BinaryOpNode node) { + Object left = dispatch(node.left); + Object right = dispatch(node.right); + + switch (node.op) { + case "+": + case "+=": + if (left instanceof String || right instanceof String) { + Object unwrappedLeft = typeSystem.unwrap(left); + Object unwrappedRight = typeSystem.unwrap(right); + + // FIX: Strip trailing zeros from BigDecimal and use toPlainString() + if (unwrappedLeft instanceof BigDecimal) { + BigDecimal bdLeft = ((BigDecimal) unwrappedLeft).stripTrailingZeros(); + unwrappedLeft = bdLeft.toPlainString(); // Use plain string, not toString() + } + if (unwrappedRight instanceof BigDecimal) { + BigDecimal bdRight = ((BigDecimal) unwrappedRight).stripTrailingZeros(); + unwrappedRight = bdRight.toPlainString(); // Use plain string, not toString() + } + + return String.valueOf(unwrappedLeft) + String.valueOf(unwrappedRight); + } + return typeSystem.addNumbers(left, right); + + case "-": + case "-=": + return typeSystem.subtractNumbers(left, right); + case "*": + case "*=": + return typeSystem.multiplyNumbers(left, right); + case "/": + case "/=": + return typeSystem.divideNumbers(left, right); + case "%": + return typeSystem.modulusNumbers(left, right); + case ">": + return typeSystem.compare(left, right) > 0; + case "<": + return typeSystem.compare(left, right) < 0; + case ">=": + return typeSystem.compare(left, right) >= 0; + case "<=": + return typeSystem.compare(left, right) <= 0; + case "=": + return right; + case "==": + // Use Object.equals() which handles BigDecimal vs BigDecimal + return typeSystem.unwrap(left).equals(typeSystem.unwrap(right)); + case "!=": + return !typeSystem.unwrap(left).equals(typeSystem.unwrap(right)); + default: + throw new RuntimeException("Unknown operator: " + node.op); + } +} + +@Override +public Object visit(BooleanChainNode node) { + boolean isAll = node.isAll; + + for (ExprNode expr : node.expressions) { + Object result = dispatch(expr); + result = typeSystem.unwrap(result); + boolean isTruthy = isTruthy(result); + + if (isAll) { + // For "all": if any expression is false, return false + if (!isTruthy) return false; + } else { + // For "any": if any expression is true, return true + if (isTruthy) return true; + } + } + + // If we get here: + // - For "all": all expressions were true, so return true + // - For "any": no expressions were true, so return false + return isAll; +} + + @Override + public Object visit(UnaryNode node) { + Object operand = dispatch(node.operand); + + switch (node.op) { + case "-": + return typeSystem.negateNumber(operand); + case "+": + return operand; + case "!": + return !isTruthy(operand); + default: + throw new RuntimeException("Unknown unary operator: " + node.op); + } + } + + @Override + public Object visit(TypeCastNode node) { + Object val = dispatch(node.expression); + if (!typeSystem.validateType(node.targetType, val)) { + return typeSystem.convertType(val, node.targetType); + } + return val; + } + + @Override + public Object visit(InputNode node) { + ExecutionContext ctx = getCurrentContext(); + Object val = ioHandler.readInput(node.targetType); + + if (node.variableName != null) { + ctx.objectInstance.fields.put(node.variableName, val); + ctx.locals.put(node.variableName, val); + } + + return val; + } + +@Override +public Object visit(ArrayNode node) { + // Handle [range] -> NaturalArray (keep this!) + if (node.elements.size() == 1) { + ExprNode onlyElement = node.elements.get(0); + if (onlyElement instanceof RangeNode) { + RangeNode range = (RangeNode) onlyElement; + return new NaturalArray(range, this); + } + } + + List result = new ArrayList(); + for (ExprNode element : node.elements) { + // Handle RangeNode specially - DON'T dispatch it! + if (element instanceof RangeNode) { + result.add(new NaturalArray((RangeNode) element, this)); + } + else { + Object evaluated = dispatch(element); + + // Special handling for nested arrays that evaluate to NaturalArray + if (element instanceof ArrayNode && evaluated instanceof NaturalArray) { + result.add(evaluated); + } + else { + result.add(evaluated); + } + } + } + return result; +} + +// Helper updated to accept BigDecimal +private Object convertToAppropriateType(BigDecimal value, Object original) { + // If original was integer/long and the result is an exact integer, return integer/long + if ((original instanceof Integer || original instanceof Long) && + (value.scale() == 0 || value.stripTrailingZeros().scale() <= 0)) { + + // Check if it fits in Integer + try { + return value.intValueExact(); + } catch (ArithmeticException e) { + // Falls back to Long if it exceeds Integer range + return value.longValue(); + } + } + + // Otherwise, return the precise BigDecimal + return value; +} + + @Override + public Object visit(TupleNode node) { + List tuple = new ArrayList(); + for (ExprNode elem : node.elements) tuple.add(dispatch(elem)); + return Collections.unmodifiableList(tuple); + } + +@Override +public Object visit(IndexAccessNode node) { + + // Get array and index objects + Object arrayObj = dispatch(node.array); + Object indexObj = dispatch(node.index); + + // Unwrap if needed + arrayObj = typeSystem.unwrap(arrayObj); + indexObj = typeSystem.unwrap(indexObj); + + // --- Handle NaturalArray --- + if (arrayObj instanceof NaturalArray) { + NaturalArray natural = (NaturalArray) arrayObj; + + // Convert index to long + long index = toLongIndex(indexObj); + + if (index < 0 || index >= natural.size()) { + throw new RuntimeException("Index out of bounds: " + index + + " for NaturalArray of size " + natural.size()); + } + + return natural.get(index); + } + + // --- Original handling for traditional lists --- + if (arrayObj instanceof List) { + int index = toIntIndex(indexObj); + + List list = (List) arrayObj; + + if (index < 0 || index >= list.size()) { + throw new RuntimeException("Index out of bounds: " + index + + " for array of size " + list.size()); + } + + return list.get(index); + } + + throw new RuntimeException("Invalid array access: expected NaturalArray or List, got " + + (arrayObj != null ? arrayObj.getClass().getSimpleName() : "null")); +} + +/** + * Convert any numeric object to long for NaturalArray indices. + */ +private long toLongIndex(Object indexObj) { + if (indexObj == null) { + throw new RuntimeException("Array index cannot be null"); + } + + if (indexObj instanceof Integer) { + return ((Integer) indexObj).longValue(); + } + + if (indexObj instanceof Long) { + return (Long) indexObj; + } + + if (indexObj instanceof Double || indexObj instanceof Float) { + double d = ((Number) indexObj).doubleValue(); + if (d != Math.floor(d)) { + throw new RuntimeException("Array index must be integer, got: Double (" + d + ")"); + } + if (d < Long.MIN_VALUE || d > Long.MAX_VALUE) { + throw new RuntimeException("Array index out of long range: " + d); + } + return (long) d; + } + + // NEW: Handle BigDecimal index precisely + if (indexObj instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) indexObj; + try { + // Use precise conversion that checks for fraction part + return bd.longValueExact(); + } catch (ArithmeticException e) { + throw new RuntimeException("Array index must be an exact integer, got: BigDecimal (" + bd + ")"); + } + } + + throw new RuntimeException("Array index must be integer, got: " + + indexObj.getClass().getSimpleName() + " (" + indexObj + ")"); +} + +/** + * Convert any numeric object to int for traditional List indices. + */ +private int toIntIndex(Object indexObj) { + if (indexObj == null) { + throw new RuntimeException("Array index cannot be null"); + } + + if (indexObj instanceof Integer) { + return (Integer) indexObj; + } + + if (indexObj instanceof Long) { + long l = (Long) indexObj; + if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { + throw new RuntimeException("Array index out of int range: " + l); + } + return (int) l; + } + + if (indexObj instanceof Double || indexObj instanceof Float) { + double d = ((Number) indexObj).doubleValue(); + if (d != Math.floor(d) || d < Integer.MIN_VALUE || d > Integer.MAX_VALUE) { + throw new RuntimeException("Array index must be integer, got: Double (" + d + ")"); + } + return (int) d; + } + + // NEW: Handle BigDecimal index precisely + if (indexObj instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) indexObj; + try { + return bd.intValueExact(); + } catch (ArithmeticException e) { + throw new RuntimeException("Array index must be an exact integer within int range, got: BigDecimal (" + bd + ")"); + } + } + + throw new RuntimeException("Array index must be integer, got: " + + indexObj.getClass().getSimpleName() + " (" + indexObj + ")"); +} + +@Override +public Object visit(AssignmentNode node) { + ExecutionContext ctx = getCurrentContext(); + Object newValue = dispatch(node.right); + + // Handle Array Index Assignment (LHS is IndexAccessNode) + if (node.left instanceof IndexAccessNode) { + IndexAccessNode indexAccess = (IndexAccessNode) node.left; + + Object arrayObj = dispatch(indexAccess.array); + arrayObj = typeSystem.unwrap(arrayObj); + + Object indexObj = dispatch(indexAccess.index); + indexObj = typeSystem.unwrap(indexObj); + + // --- Handle NaturalArray --- + if (arrayObj instanceof NaturalArray) { + NaturalArray natural = (NaturalArray) arrayObj; + long index = toLongIndex(indexObj); + + if (index < 0 || index >= natural.size()) { + throw new RuntimeException("Index out of bounds: " + index + + " for NaturalArray of size " + natural.size()); + } + + natural.set(index, newValue); + return newValue; + } + + // --- Handle traditional List --- + if (arrayObj instanceof List) { + int intIndex = toIntIndex(indexObj); + + List list = (List) arrayObj; + + if (intIndex < 0 || intIndex >= list.size()) { + throw new RuntimeException("Array index out of bounds: " + intIndex + + " (array size: " + list.size() + ")"); + } + + list.set(intIndex, newValue); + return newValue; + } + + throw new RuntimeException("Invalid assignment target: Cannot index non-array object. " + + "Expected NaturalArray or List, got: " + + (arrayObj != null ? arrayObj.getClass().getSimpleName() : "null")); + } + + // Handle Variable Assignment (LHS is a variable name) + else if (node.left.name != null) { + String varName = node.left.name; + + // REJECT assignment to underscore + if ("_".equals(varName)) { + throw new RuntimeException("Cannot assign to '_'. Underscore is reserved for discard/placeholder."); + } + + // 1. Check Locals (REASSIGNMENT only - declarations use := elsewhere) + if (ctx.locals.containsKey(varName)) { + if (ctx.localTypes.containsKey(varName)) { + String type = ctx.localTypes.get(varName); + if (!typeSystem.validateType(type, newValue)) { + throw new RuntimeException("Type mismatch in assignment. Variable '" + + varName + "' expects " + type + ", got: " + newValue); + } + if (type.contains("|")) { + String activeType = typeSystem.getConcreteType(typeSystem.unwrap(newValue)); + newValue = new TypedValue(newValue, activeType, type); + } + } + ctx.locals.put(varName, newValue); + return newValue; + } + + // 2. Check Object Fields + if (ctx.objectInstance.fields.containsKey(varName)) { + ctx.objectInstance.fields.put(varName, newValue); + return newValue; + } + + // 3. ERROR: Variable doesn't exist (use := for declaration) + throw new RuntimeException("Cannot assign to undefined variable: " + varName + + ". Use ':=' for declaration: " + varName + " := " + node.right); + } + + // Handle Slot Assignment in method returns? (If AssignmentNode is used there) + // Actually, SlotAssignmentNode is separate, so not here + + throw new RuntimeException("Invalid assignment target: " + + (node.left != null ? node.left.getClass().getSimpleName() : "null")); +} + + @Override + public Object visit(SlotDeclarationNode node) { + return null; + } + + @Override + public Object visit(MethodCallNode node) { + if (node.chainType != null && node.chainArguments != null) return evaluateConditionalChain(node); + ExecutionContext ctx = getCurrentContext(); + + MethodNode method = null; + if (ctx.objectInstance.type != null) { + for (MethodNode m : ctx.objectInstance.type.methods) { + if (m.name.equals(node.name)) { method = m; break; } + } + } + + Object result = interpreter.evalMethodCall(node, ctx.objectInstance, ctx.locals); + + if (node.slotNames != null && !node.slotNames.isEmpty()) { + if (!(result instanceof Map)) { + throw new RuntimeException("Cannot extract slot '" + node.slotNames.get(0) + "'. Method did not return slots."); + } + + Map map = (Map) result; + String requestedSlot = node.slotNames.get(0); + + if (!map.containsKey(requestedSlot) && method != null && method.returnSlots != null) { + try { + int index = Integer.parseInt(requestedSlot); + if (index >= 0 && index < method.returnSlots.size()) { + requestedSlot = method.returnSlots.get(index).name; + } + } catch (NumberFormatException e) { + // It was a non-numeric name, proceed to standard check. + } + } + + if (map.containsKey(requestedSlot)) { + return map.get(requestedSlot); + } else { + throw new RuntimeException("Undefined method slot: " + requestedSlot); + } + } + + return result; + } + +@Override +public Object visit(MultipleSlotAssignmentNode node) { + ExecutionContext ctx = getCurrentContext(); + + List declaredSlots = new ArrayList(ctx.slotTypes.keySet()); + + Object lastValue = null; + int slotIndex = 0; + + for (SlotAssignmentNode assign : node.assignments) { + Object value = dispatch(assign.value); + + String target; + if (assign.slotName != null && !assign.slotName.isEmpty() && !"_".equals(assign.slotName)) { + target = assign.slotName; + } else { + if (slotIndex < declaredSlots.size()) { + target = declaredSlots.get(slotIndex); + } else { + throw new RuntimeException("Too many positional slot assignments. Method has only " + declaredSlots.size() + " return slots."); + } + } + + if (ctx.slotValues.containsKey(target)) { + String declaredType = ctx.slotTypes.get(target); + + validateSlotType(ctx, target, value); + + if (declaredType.contains("|")) { + String activeType = typeSystem.getConcreteType(typeSystem.unwrap(value)); + value = new TypedValue(value, activeType, declaredType); + } + + ctx.slotValues.put(target, value); + ctx.slotsInCurrentPath.add(target); + } else { + throw new RuntimeException("Assignment to '" + target + "' failed: Slot is not declared."); + } + lastValue = value; + slotIndex++; + } + return lastValue; +} + +@Override +public Object visit(SlotAssignmentNode node) { + ExecutionContext ctx = getCurrentContext(); + Object value = dispatch(node.value); + String varName = node.slotName; + + String slotTarget; + if (varName != null && !varName.isEmpty() && !"_".equals(varName)) { + slotTarget = varName; + } else { + if (ctx.slotValues != null && !ctx.slotValues.isEmpty()) { + slotTarget = ctx.slotTypes.keySet().iterator().next(); + } else { + throw new RuntimeException("Assignment to implicit return failed: Method has no declared return slots."); + } + } + + if (ctx.slotValues != null && ctx.slotValues.containsKey(slotTarget)) { + String declaredType = ctx.slotTypes.get(slotTarget); + + validateSlotType(ctx, slotTarget, value); + + if (declaredType.contains("|")) { + String activeType = typeSystem.getConcreteType(typeSystem.unwrap(value)); + value = new TypedValue(value, activeType, declaredType); + } + + ctx.slotValues.put(slotTarget, value); + ctx.slotsInCurrentPath.add(slotTarget); + + } else { + throw new RuntimeException("Assignment to '" + (varName != null ? varName : "implicit") + "' failed: Slot '" + slotTarget + "' is not declared."); + } + return value; +} + + @Override + public Object visit(FieldNode node) { + Object val = node.value != null ? dispatch(node.value) : null; + getCurrentContext().objectInstance.fields.put(node.name, val); + return val; + } + + @Override + public Object visit(VarNode node) { + Object val = node.value != null ? dispatch(node.value) : null; + + if (node.explicitType != null) { + String declaredType = node.explicitType; + + getCurrentContext().localTypes.put(node.name, declaredType); + + if (!typeSystem.validateType(declaredType, val)) { + throw new RuntimeException("Type mismatch for variable " + node.name + ". Expected " + declaredType); + } + + if (declaredType.contains("|")) { + String activeType = typeSystem.getConcreteType(typeSystem.unwrap(val)); + val = new TypedValue(val, activeType, declaredType); + } + } + + getCurrentContext().locals.put(node.name, val); + return val; + } + + @Override + public Object visit(OutputNode node) { + Object lastVal = null; + for (ExprNode arg : node.arguments) { + Object val = dispatch(arg); + + val = typeSystem.unwrap(val); + + ioHandler.output(val); + lastVal = val; + } + return lastVal; + } + + @Override + public Object visit(ExitNode node) { + throw new Interpreter.EarlyExitException(); + } + + @Override + public Object visit(StmtIfNode node) { + Object testObj = dispatch(node.condition); + testObj = typeSystem.unwrap(testObj); + + boolean test = isTruthy(testObj); + List branch = test ? node.thenBlock.statements : node.elseBlock.statements; + + ExecutionContext ctx = getCurrentContext(); + Set prevSlots = new HashSet(ctx.slotsInCurrentPath); + + for (StmtNode s : branch) { + dispatch(s); + if (!ctx.slotsInCurrentPath.isEmpty() && interpreter.shouldReturnEarly(ctx.slotValues, ctx.slotsInCurrentPath)) break; + } + ctx.slotsInCurrentPath = prevSlots; + return null; + } + + @Override +public Object visit(ExprIfNode node) { + Object condValue = dispatch(node.condition); + condValue = typeSystem.unwrap(condValue); + + if (isTruthy(condValue)) { + return dispatch(node.thenExpr); + } else { + return dispatch(node.elseExpr); + } +} + +// UPDATED: ForNode uses BigDecimal for multiplicative/division loops +@Override +public Object visit(ForNode node) { + ExecutionContext ctx = getCurrentContext(); + String iter = node.iterator; + + Object startObj = dispatch(node.range.start); + Object endObj = dispatch(node.range.end); + + startObj = typeSystem.unwrap(startObj); + endObj = typeSystem.unwrap(endObj); + + // Check if step is multiplicative/division (i * 2, i / 2) + if (node.range.step != null && node.range.step instanceof BinaryOpNode) { + BinaryOpNode binOp = (BinaryOpNode) node.range.step; + + if (binOp.left instanceof ExprNode && + ((ExprNode)binOp.left).name != null && + ((ExprNode)binOp.left).name.equals(iter) && + (binOp.op.equals("*") || binOp.op.equals("/"))) { + + Object rightObj = dispatch(binOp.right); + rightObj = typeSystem.unwrap(rightObj); + + // Use BigDecimal for factor to support precise multiplicative/divisive steps (e.g., *1.01) + BigDecimal factorBD = typeSystem.toBigDecimal(rightObj); + + if (factorBD.compareTo(BigDecimal.ZERO) == 0 && binOp.op.equals("/")) { + throw new RuntimeException("Division by zero in loop step"); + } + + return executeMultiplicativeLoop(ctx, node, startObj, endObj, factorBD, binOp.op); + } + } + + // Regular additive step + BigDecimal stepBD = BigDecimal.ONE; + if (node.range.step != null) { + Object stepObj = dispatch(node.range.step); + stepObj = typeSystem.unwrap(stepObj); + stepBD = typeSystem.toBigDecimal(stepObj); + } else { + // Default step based on direction + BigDecimal startBD = typeSystem.toBigDecimal(startObj); + BigDecimal endBD = typeSystem.toBigDecimal(endObj); + stepBD = (startBD.compareTo(endBD) > 0) ? BigDecimal.ONE.negate() : BigDecimal.ONE; + } + + if (stepBD.compareTo(BigDecimal.ZERO) == 0) throw new RuntimeException("Loop step cannot be zero."); + + return executeAdditiveLoop(ctx, node, startObj, endObj, stepBD); +} + +// UPDATED: executeAdditiveLoop to use BigDecimal +private Object executeAdditiveLoop(ExecutionContext ctx, ForNode node, + Object startObj, Object endObj, BigDecimal stepBD) { + String iter = node.iterator; + + BigDecimal startBD = typeSystem.toBigDecimal(startObj); + BigDecimal endBD = typeSystem.toBigDecimal(endObj); + BigDecimal current = startBD; + + boolean increasing = stepBD.compareTo(BigDecimal.ZERO) > 0; + + while (true) { + // Check termination condition using precise comparison + if (increasing && current.compareTo(endBD) > 0) break; + if (!increasing && current.compareTo(endBD) < 0) break; + + // Store the current value, converting back to Integer/Long if possible + Object currentValue = convertToAppropriateType(current, startObj); + + ctx.locals.put(iter, currentValue); + if (!ctx.localTypes.containsKey(iter)) { + // Use INT if it's an exact integer, otherwise FLOAT + String inferredType = (currentValue instanceof Integer || currentValue instanceof Long) ? INT.toString() : FLOAT.toString(); + ctx.localTypes.put(iter, inferredType); + } + + for (StmtNode s : node.body.statements) { + dispatch(s); + if (!ctx.slotsInCurrentPath.isEmpty() && + interpreter.shouldReturnEarly(ctx.slotValues, ctx.slotsInCurrentPath)) { + return null; + } + } + + // Update iterator precisely + current = current.add(stepBD); + } + return null; +} + +// UPDATED: executeMultiplicativeLoop to use BigDecimal +private Object executeMultiplicativeLoop(ExecutionContext ctx, ForNode node, + Object startObj, Object endObj, + BigDecimal factorBD, String operation) { + String iter = node.iterator; + + BigDecimal startBD = typeSystem.toBigDecimal(startObj); + BigDecimal endBD = typeSystem.toBigDecimal(endObj); + BigDecimal current = startBD; + + while (true) { + // Check termination condition based on operation and direction + boolean shouldContinue = false; + + if (operation.equals("*")) { + if (factorBD.compareTo(BigDecimal.ONE) > 0) { + // Growing sequence + shouldContinue = (startBD.compareTo(endBD) < 0) ? current.compareTo(endBD) <= 0 : current.compareTo(endBD) >= 0; + } else if (factorBD.compareTo(BigDecimal.ZERO) > 0 && factorBD.compareTo(BigDecimal.ONE) < 0) { + // Shrinking sequence + shouldContinue = (startBD.compareTo(endBD) > 0) ? current.compareTo(endBD) >= 0 : current.compareTo(endBD) <= 0; + } else { + throw new RuntimeException("Unsupported multiplication factor in loops"); + } + } else if (operation.equals("/")) { + + if (factorBD.compareTo(BigDecimal.ONE) > 0) { + // Shrinking sequence (multiplying by a fraction) + shouldContinue = (startBD.compareTo(endBD) > 0) ? current.compareTo(endBD) >= 0 : current.compareTo(endBD) <= 0; + } else if (factorBD.compareTo(BigDecimal.ZERO) > 0 && factorBD.compareTo(BigDecimal.ONE) < 0) { + // Growing sequence (multiplying by a number > 1) + shouldContinue = (startBD.compareTo(endBD) < 0) ? current.compareTo(endBD) <= 0 : current.compareTo(endBD) >= 0; + } else { + throw new RuntimeException("Unsupported division factor in loops"); + } + } + + if (!shouldContinue) break; + + // Store current value + Object currentValue = convertToAppropriateType(current, startObj); + + ctx.locals.put(iter, currentValue); + if (!ctx.localTypes.containsKey(iter)) { + String inferredType = (currentValue instanceof Integer || currentValue instanceof Long) ? INT.toString() : FLOAT.toString(); + ctx.localTypes.put(iter, inferredType); + } + + for (StmtNode s : node.body.statements) { + dispatch(s); + if (!ctx.slotsInCurrentPath.isEmpty() && + interpreter.shouldReturnEarly(ctx.slotValues, ctx.slotsInCurrentPath)) { + return null; + } + } + + // Apply precise multiplicative operation + if (operation.equals("*")) { + current = current.multiply(factorBD); + } else if (operation.equals("/")) { + current = current.divide(factorBD, DECIMAL_SCALE, RoundingMode.HALF_UP); + } + } + return null; +} + + @Override +public Object visit(ReturnSlotAssignmentNode node) { + ExecutionContext ctx = getCurrentContext(); + Object res = interpreter.evalMethodCall(node.methodCall, ctx.objectInstance, ctx.locals); + + if (res instanceof Map) { + Map map = (Map) res; + + MethodNode method = null; + if (ctx.objectInstance.type != null) { + for (MethodNode m : ctx.objectInstance.type.methods) { + if (m.name.equals(node.methodCall.name)) { + method = m; + break; + } + } + } + + for (int i = 0; i < node.variableNames.size(); i++) { + String slot = node.methodCall.slotNames.get(i); + + String requestedSlot = slot; + if (!map.containsKey(requestedSlot) && method != null && method.returnSlots != null) { + try { + int index = Integer.parseInt(requestedSlot); + if (index >= 0 && index < method.returnSlots.size()) { + requestedSlot = method.returnSlots.get(index).name; + } + } catch (NumberFormatException e) { + } + } + + if (map.containsKey(requestedSlot)) { + Object val = map.get(requestedSlot); + ctx.locals.put(node.variableNames.get(i), val); + } else { + throw new RuntimeException("Missing slot: " + slot + " (resolved as: " + requestedSlot + ")"); + } + } + } else { + throw new RuntimeException("Method did not return slot values"); + } + return res; +} + + private Object evaluateConditionalChain(MethodCallNode call) { + boolean result = ALL.toString().equals(call.chainType); + + for (ExprNode arg : call.chainArguments) { + MethodCallNode currentCall = ASTFactory.createMethodCall(call.name, call.qualifiedName); + currentCall.arguments = new ArrayList(); + + if (arg instanceof ArgumentListNode) { + currentCall.arguments.addAll(((ArgumentListNode) arg).arguments); + } else { + currentCall.arguments.add(arg); + } + + boolean negated = false; + + if (arg instanceof UnaryNode && "!".equals(((UnaryNode) arg).op)) { + negated = true; + } + + Object methodResultObj = dispatch(currentCall); + methodResultObj = typeSystem.unwrap(methodResultObj); + + boolean methodResult = isTruthy(methodResultObj); + boolean finalResult = negated ? !methodResult : methodResult; + + if (ALL.toString().equals(call.chainType)) { + if (!finalResult) return false; + } else { + if (finalResult) return true; + } + } + return result; + } + +private boolean isTruthy(Object value) { + if (value instanceof TypedValue) throw new RuntimeException("isTruthy called on unwrapped value."); + + if (value == null) return false; + if (value instanceof Boolean) return (Boolean) value; + if (value instanceof Number) { + if (value instanceof BigDecimal) return ((BigDecimal) value).compareTo(BigDecimal.ZERO) != 0; + return ((Number) value).doubleValue() != 0.0; + } + if (value instanceof String) { + String str = (String) value; + if (str.equalsIgnoreCase("true")) return true; + if (str.equalsIgnoreCase("false")) return false; + return !str.isEmpty(); + } + if (value instanceof List) return !((List) value).isEmpty(); + if (value instanceof NaturalArray) return ((NaturalArray) value).size() > 0; + return true; +} + + private void validateSlotType(ExecutionContext ctx, String slotName, Object value) { + if (ctx.slotTypes == null || !ctx.slotTypes.containsKey(slotName) || value == null) return; + String type = ctx.slotTypes.get(slotName); + if (!typeSystem.validateType(type, value)) { + throw new RuntimeException("Type mismatch: " + slotName + " expected " + type); + } + } +} \ No newline at end of file diff --git a/src/main/java/cod/interpreter/NaturalArray.java b/src/main/java/cod/interpreter/NaturalArray.java new file mode 100644 index 00000000..963732e6 --- /dev/null +++ b/src/main/java/cod/interpreter/NaturalArray.java @@ -0,0 +1,627 @@ +package cod.interpreter; + +import cod.ast.nodes.*; +import java.util.*; +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class NaturalArray { + + // Core formula + private final RangeNode baseRange; + private final InterpreterVisitor visitor; + + // Mutation support + private Map cache; + private boolean isMutable = false; + + // Cached calculations - PRESERVE ORIGINAL TYPES + private Object cachedStart = null; + private Object cachedEnd = null; + private Object cachedStep = null; + private Long cachedSize = null; + + // Type tracking (Determines if we use fast long arithmetic or precise BigDecimal) + private boolean isLongOrIntegerRange = false; + + // === HIERARCHICAL LEXICOGRAPHICAL RANGE FIELDS === + private boolean isLexicographicalRange = false; + private String startString = null; + private String endString = null; + + // === PERFORMANCE OPTIMIZATIONS === + private Long cachedStartLong = null; + private Long cachedStepLong = null; + private BigDecimal cachedStartBD = null; + private BigDecimal cachedStepBD = null; + + // Single-element cache for sequential access + private transient Long lastIndex = null; + private transient Object lastValue = null; + + // Precomputed powers of 26 for performance (up to length 10) + private static final long[] POWERS_26 = new long[11]; + private static final long[] POWERS_2 = new long[11]; + private static final long[] TOTAL_UP_TO_LENGTH = new long[11]; + + static { + // Precompute for performance + POWERS_26[0] = 1; + POWERS_2[0] = 1; + for (int i = 1; i <= 10; i++) { + POWERS_26[i] = POWERS_26[i-1] * 26; + POWERS_2[i] = POWERS_2[i-1] * 2; + } + + // Total sequences up to each length: sum_{i=1}^{len} (2^i × 26^i) + TOTAL_UP_TO_LENGTH[0] = 0; + for (int len = 1; len <= 10; len++) { + TOTAL_UP_TO_LENGTH[len] = TOTAL_UP_TO_LENGTH[len-1] + + POWERS_2[len] * POWERS_26[len]; + } + } + + public NaturalArray(RangeNode range, InterpreterVisitor visitor) { + this.baseRange = range; + this.visitor = visitor; + this.cache = null; + this.isMutable = false; + + // Eagerly check type on construction + getStart(); + getEnd(); + getStep(); + + // Check if this is a lexicographical range + // A range is lexicographical if start and end are strings AND step is 1 or implicit (null) + if (cachedStart instanceof String && cachedEnd instanceof String && + (baseRange.step == null || (cachedStep instanceof Long && ((Long)cachedStep).longValue() == 1L))) { + + this.isLexicographicalRange = true; + this.startString = (String) cachedStart; + this.endString = (String) cachedEnd; + this.isLongOrIntegerRange = false; // Must be false for string range + + // Validate the alphabet. We allow only a-z and A-Z. + if (!isValidLexString(startString) || !isValidLexString(endString)) { + throw new RuntimeException("Lexicographical range bounds must contain only letters (a-z, A-Z)."); + } + + // For hierarchical ordering, start must be <= end + long startIdx = hierarchicalSequenceToIndex(startString); + long endIdx = hierarchicalSequenceToIndex(endString); + if (startIdx > endIdx) { + throw new RuntimeException("Lexicographical range start must come before end in hierarchical ordering."); + } + } + } + + // --- IMMUTABLE OPERATIONS --- + + public Object get(long index) { + checkBounds(index); + + // 1. Single-element cache (extremely fast for sequential access) + if (lastIndex != null && lastIndex == index) { + return lastValue; + } + + // 2. FAST PATH: If not mutable, calculate directly (no HashMap checks!) + if (!isMutable) { + Object result = calculateValue(index); + lastIndex = index; + lastValue = result; + return result; + } + + // 3. Only check cache if we're actually mutable + if (cache != null) { + Object val = cache.get(index); // Single HashMap lookup + if (val != null) { + lastIndex = index; + lastValue = val; + return val; + } + } + + // 4. Calculate and cache + Object result = calculateValue(index); + lastIndex = index; + lastValue = result; + return result; + } + + public long size() { + if (cachedSize != null) return cachedSize; + + if (isLexicographicalRange) { + // HIERARCHICAL Lexicographical Size + long size = calculateLexSize(); + cachedSize = size; + return size; + } + + if (isLongOrIntegerRange) { + // Use fast long arithmetic with cached values + long startVal = getStartLong(); + long endVal = getEndLong(); + long stepVal = getStepLong(); + + if (stepVal == 0) { cachedSize = 0L; return 0; } + if ((stepVal > 0 && startVal > endVal) || (stepVal < 0 && startVal < endVal)) { + cachedSize = 0L; return 0; + } + + // Fix: Add 1 correctly for the range + long diff = Math.abs(endVal - startVal); + long count = diff / Math.abs(stepVal) + 1; + cachedSize = count; + return count; + } + + // Use precise BigDecimal arithmetic + BigDecimal startBD = getStartBD(); + BigDecimal endBD = getEndBD(); + BigDecimal stepBD = getStepBD(); + + if (stepBD.compareTo(BigDecimal.ZERO) == 0) { + cachedSize = 0L; + return 0; + } + + // Check if range is valid + boolean increasing = stepBD.compareTo(BigDecimal.ZERO) > 0; + if ((increasing && startBD.compareTo(endBD) > 0) || (!increasing && startBD.compareTo(endBD) < 0)) { + cachedSize = 0L; + return 0; + } + + // Calculate size: abs((end - start) / step) + 1 + BigDecimal diff = endBD.subtract(startBD); + BigDecimal absStep = stepBD.abs(); + + BigDecimal sizeBD = diff.abs().divide(absStep, 0, RoundingMode.DOWN).add(BigDecimal.ONE); + + // Check if it fits in long + if (sizeBD.compareTo(new BigDecimal(Long.MAX_VALUE)) > 0) { + throw new RuntimeException("Array size too large: exceeds long maximum."); + } + + long size = sizeBD.longValue(); + cachedSize = size; + return size; + } + + // --- MUTABLE OPERATIONS --- + + public void set(long index, Object value) { + checkBounds(index); + + // Clear single-element cache (it's now invalid) + lastIndex = null; + lastValue = null; + + if (!isMutable) { + becomeMutable(); + } + + if (cache == null) { + cache = new HashMap(); + } + + cache.put(index, value); + } + + // --- PRIVATE HELPERS --- + + private void checkBounds(long index) { + if (index < 0 || index >= size()) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size()); + } + } + + private Object calculateValue(long index) { + if (isLexicographicalRange) { + // HIERARCHICAL Lexicographical Value Calculation + return calculateLexValue(index); + } + + if (isLongOrIntegerRange) { + // Use CACHED long arithmetic for integer/long ranges (fast path) + long startVal = getStartLong(); + long stepVal = getStepLong(); + long result = startVal + index * stepVal; + + if (cachedStart instanceof Integer && result >= Integer.MIN_VALUE && result <= Integer.MAX_VALUE) { + return (int) result; + } + return result; + } + + // Use precise BigDecimal arithmetic for floating point ranges + BigDecimal startBD = getStartBD(); + BigDecimal stepBD = getStepBD(); + BigDecimal indexBD = BigDecimal.valueOf(index); + + // Calculation: start + index * step + BigDecimal resultBD = startBD.add(indexBD.multiply(stepBD)); + + // Return the BigDecimal object + return resultBD; + } + + // === PERFORMANCE OPTIMIZATION METHODS === + + private long getStartLong() { + if (cachedStartLong == null) { + cachedStartLong = toLong(getStart()); + } + return cachedStartLong; + } + + private long getStepLong() { + if (cachedStepLong == null) { + cachedStepLong = toLong(getStep()); + } + return cachedStepLong; + } + + private long getEndLong() { + // Not cached by default, but used in size() + return toLong(getEnd()); + } + + private BigDecimal getStartBD() { + if (cachedStartBD == null) { + cachedStartBD = toBigDecimal(getStart()); + } + return cachedStartBD; + } + + private BigDecimal getStepBD() { + if (cachedStepBD == null) { + cachedStepBD = toBigDecimal(getStep()); + } + return cachedStepBD; + } + + private BigDecimal getEndBD() { + // Not cached by default, but used in size() + return toBigDecimal(getEnd()); + } + + // === HIERARCHICAL LEXICOGRAPHICAL LOGIC (OPTIMIZED & MERGED) === + + private boolean isValidLexString(String s) { + for (char c : s.toCharArray()) { + if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')) { + return false; + } + } + return true; + } + + /** + * HIERARCHICAL: Converts string to its global index. (OPTIMIZED SINGLE-PASS) + */ + private long hierarchicalSequenceToIndex(String s) { + int n = s.length(); + if (n > 10) { + throw new RuntimeException("String too long for lexicographical range (max 10 characters)"); + } + + // 1. Add all sequences of shorter lengths + long index = TOTAL_UP_TO_LENGTH[n - 1]; + + // 2. SINGLE PASS: Compute pattern AND content simultaneously + long patternMask = 0; + long contentIndex = 0; + + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + + // Fast uppercase check (ASCII: 'A'-'Z' < 'a') + boolean isUpper = c < 'a'; + + if (isUpper) { + // Set pattern bit (MSB is position 0) + patternMask |= (1L << (n - 1 - i)); + + // Fast lowercase conversion for content calculation + c += 32; + } + + // Fast char to 0-25 digit (ASCII math: 'a'-'a'=0) + int digit = c - 'a'; + + // Base 26 content calculation (Horner's method) + contentIndex = contentIndex * 26 + digit; + } + + // 3. Position: index + patternIndex * 26^n + contentIndex + return index + (patternMask * POWERS_26[n]) + contentIndex; + } + + /** + * HIERARCHICAL: Converts global index back to string. (OPTIMIZED SINGLE-PASS) + */ + private String hierarchicalIndexToSequence(long globalIndex) { + // 1. Find length n + int n = 1; + while (n <= 10 && globalIndex >= TOTAL_UP_TO_LENGTH[n]) { + n++; + } + + if (n > 10) { + throw new RuntimeException("Index too large for lexicographical range"); + } + + // 2. Index within length group + long indexInLengthGroup = globalIndex - TOTAL_UP_TO_LENGTH[n - 1]; + + // 3. Split into pattern and content + long stringsPerPattern = POWERS_26[n]; + long patternIndex = indexInLengthGroup / stringsPerPattern; + long contentIndex = indexInLengthGroup % stringsPerPattern; + + // 4. Convert contentIndex to base-26 digits and build array (Right-to-Left) + char[] chars = new char[n]; + long temp = contentIndex; + + for (int i = n - 1; i >= 0; i--) { + int digit = (int)(temp % 26); + chars[i] = (char)('a' + digit); // Base lowercase character + temp /= 26; + } + + // 5. Apply case pattern using fast bit checks + for (int i = 0; i < n; i++) { + // Check uppercase bit: MSB = position 0 (first character) + if (((patternIndex >> (n - 1 - i)) & 1) == 1) { + // Fast uppercase: clear bit 5 (32) + chars[i] &= ~32; + } + } + + return new String(chars); + } + + /** + * Calculate lexicographical size using HIERARCHICAL ordering. + */ + private long calculateLexSize() { + long startIndex = hierarchicalSequenceToIndex(startString); + long endIndex = hierarchicalSequenceToIndex(endString); + + return endIndex - startIndex + 1; + } + + /** + * Calculate lexicographical value using HIERARCHICAL ordering. + */ + private String calculateLexValue(long index) { + long startIndex = hierarchicalSequenceToIndex(startString); + long targetIndex = startIndex + index; + return hierarchicalIndexToSequence(targetIndex); + } + + private void becomeMutable() { + this.isMutable = true; + } + + // FIXED: Now detects integer BigDecimal ranges for fast path + private Object getStart() { + if (cachedStart != null) return cachedStart; + Object startObj = visitor.dispatch(baseRange.start); + + // Check if it's an integer (Integer, Long, or integer BigDecimal) + if (startObj instanceof Integer || startObj instanceof Long) { + isLongOrIntegerRange = true; + } else if (startObj instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) startObj; + // Check if it's an exact integer + try { + bd.longValueExact(); // Will throw if not integer + isLongOrIntegerRange = true; // Integer BigDecimal! + } catch (ArithmeticException e) { + isLongOrIntegerRange = false; // Fractional BigDecimal + } + } else { + isLongOrIntegerRange = false; + } + + cachedStart = startObj; + return cachedStart; + } + + // FIXED: Now handles BigDecimal in type detection + private Object getEnd() { + if (cachedEnd != null) return cachedEnd; + Object endObj = visitor.dispatch(baseRange.end); + + // Update isLongOrIntegerRange based on end type + if (isLongOrIntegerRange) { // Only update if still true + if (!(endObj instanceof Integer || endObj instanceof Long)) { + if (endObj instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) endObj; + try { + bd.longValueExact(); // Check if integer + // Keep isLongOrIntegerRange = true + } catch (ArithmeticException e) { + isLongOrIntegerRange = false; // Fractional + } + } else { + isLongOrIntegerRange = false; + } + } + } + + cachedEnd = endObj; + return cachedEnd; + } + + // FIXED: Now handles BigDecimal in type detection + private Object getStep() { + if (cachedStep != null) return cachedStep; + + if (baseRange.step != null) { + Object stepObj = visitor.dispatch(baseRange.step); + + // Update isLongOrIntegerRange based on step type + if (isLongOrIntegerRange) { // Only update if still true + if (!(stepObj instanceof Integer || stepObj instanceof Long)) { + if (stepObj instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) stepObj; + try { + bd.longValueExact(); // Check if integer + // Keep isLongOrIntegerRange = true + } catch (ArithmeticException e) { + isLongOrIntegerRange = false; // Fractional + } + } else { + isLongOrIntegerRange = false; + } + } + } + + cachedStep = stepObj; + } else { + // Default step calculation (always 1 or -1) is always integer/long + + if (isLongOrIntegerRange) { + long startVal = getStartLong(); + long endVal = getEndLong(); + cachedStep = (startVal <= endVal) ? 1L : -1L; + } else { + // If not integer range, but no step is given, still default to 1.0 or -1.0 + BigDecimal startVal = getStartBD(); + BigDecimal endVal = getEndBD(); + cachedStep = (startVal.compareTo(endVal) <= 0) ? BigDecimal.ONE : BigDecimal.ONE.negate(); + } + } + + return cachedStep; + } + + // FIXED: Better handling of BigDecimal to long conversion + private long toLong(Object obj) { + if (obj instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) obj; + if (isLongOrIntegerRange) { + // Only require exact for integer ranges + try { + return bd.longValueExact(); + } catch (ArithmeticException e) { + throw new RuntimeException("Cannot convert non-integer BigDecimal to long: " + bd); + } + } else { + // For fractional ranges, truncate (but this shouldn't be called in that case) + return bd.longValue(); + } + } + if (obj instanceof Integer) return ((Integer) obj).longValue(); + if (obj instanceof Long) return (Long) obj; + throw new RuntimeException("Cannot convert to long: " + obj); + } + + private BigDecimal toBigDecimal(Object obj) { + if (obj instanceof BigDecimal) return (BigDecimal) obj; + if (obj instanceof String) { + // Check if we're in a lexicographical range context + if (cachedStart instanceof String || cachedEnd instanceof String) { + // For lexicographical ranges, return a default value + // This prevents the error when calculating size or other numeric operations + return BigDecimal.ZERO; + } + throw new RuntimeException("Cannot convert string to BigDecimal for numeric calculation."); + } + return BigDecimal.valueOf(((Number)obj).doubleValue()); + } + + // --- UTILITIES --- + + public boolean isMutable() { + return isMutable; + } + + public int getCacheSize() { + return cache != null ? cache.size() : 0; + } + + public double getCacheRatio() { + long size = size(); + if (size == 0) return 0.0; + return cache != null ? (double) cache.size() / size : 0.0; + } + + @Override + public String toString() { + // Always show as formula, never materialize + Object start = getStart(); + Object end = getEnd(); + Object step = getStep(); + + String formula; + + if (isLexicographicalRange) { + formula = String.format("LexArray[\"%s\" to \"%s\"]", start, end); + } else { + formula = String.format("NaturalArray[%s to %s", start, end); + } + + boolean isDefaultStep = false; + if (!isLexicographicalRange) { + if (isLongOrIntegerRange) { + long s = getStepLong(); + long st = getStartLong(); + long en = getEndLong(); + isDefaultStep = (s == 1L && st <= en) || (s == -1L && st > en); + } else { + BigDecimal s = getStepBD(); + BigDecimal st = getStartBD(); + BigDecimal en = getEndBD(); + boolean increasing = st.compareTo(en) <= 0; + isDefaultStep = (s.compareTo(BigDecimal.ONE) == 0 && increasing) || (s.compareTo(BigDecimal.ONE.negate()) == 0 && !increasing); + } + } + + if (!isDefaultStep) { + formula += " step " + step; + } + + if (!isLexicographicalRange) { + formula += "]"; + } + + // Add state info + formula += String.format(" (size: %d", size()); + if (isMutable) { + formula += ", mutable, cache: " + getCacheSize() + "/" + size(); + } else { + formula += ", immutable"; + } + formula += ")"; + + // For VERY small arrays, optionally show values + if (size() <= 5) { + StringBuilder sb = new StringBuilder("["); + for (long i = 0; i < size(); i++) { + if (i > 0) sb.append(", "); + sb.append(get(i)); + } + sb.append("]"); + return sb.toString(); + } + + return formula; + } + + // Convert to traditional List (eager materialization) + public List toList() { + List result = new ArrayList(); + for (long i = 0; i < size(); i++) { + result.add(get(i)); + } + return result; + } +} \ No newline at end of file diff --git a/src/main/java/cod/interpreter/ObjectInstance.java b/src/main/java/cod/interpreter/ObjectInstance.java index 902d1338..2496ded3 100644 --- a/src/main/java/cod/interpreter/ObjectInstance.java +++ b/src/main/java/cod/interpreter/ObjectInstance.java @@ -11,4 +11,4 @@ public class ObjectInstance { public ObjectInstance(TypeNode type) { this.type = type; } -} +} \ No newline at end of file diff --git a/src/main/java/cod/interpreter/TypeSystem.java b/src/main/java/cod/interpreter/TypeSystem.java index aac2ef10..e42409a9 100644 --- a/src/main/java/cod/interpreter/TypeSystem.java +++ b/src/main/java/cod/interpreter/TypeSystem.java @@ -1,151 +1,358 @@ package cod.interpreter; -import cod.debug.DebugSystem; +import static cod.syntax.Keyword.*; +import java.util.ArrayList; import java.util.List; +import java.math.BigDecimal; +import java.math.RoundingMode; public class TypeSystem { - // ADD TYPE CONVERSION METHOD - public Object convertType(Object value, String targetType) { - try { - switch (targetType) { - case "int": - if (value instanceof Integer) return value; - if (value instanceof Float) return ((Float) value).intValue(); - if (value instanceof Double) return ((Double) value).intValue(); - if (value instanceof String) return Integer.parseInt((String) value); - return (int) toDouble(value); - - case "float": - if (value instanceof Float) return value; - return (float) toDouble(value); - - case "string": - return String.valueOf(value); - - case "bool": - if (value instanceof Boolean) return value; - if (value instanceof String) { - String str = ((String) value).toLowerCase(); - return str.equals("true") || str.equals("1") || str.equals("yes"); - } - return toDouble(value) != 0; - - default: - return value; // Unknown type, return as-is - } - } catch (Exception e) { - DebugSystem.error("TYPECAST", "Failed to convert " + value + " to " + targetType); - throw new RuntimeException("Type conversion failed: " + value + " to " + targetType); - } - } + // Scale for BigDecimal operations (can be adjusted for higher precision) + private static final int DECIMAL_SCALE = 20; - public int compare(Object a, Object b) { - double da = toDouble(a); - double db = toDouble(b); - return Double.compare(da, db); + public Object unwrap(Object obj) { + if (obj instanceof TypedValue) { + return ((TypedValue) obj).value; + } + return obj; } public Object addNumbers(Object a, Object b) { - if (a instanceof Integer && b instanceof Integer) return (Integer) a + (Integer) b; - double result = toDouble(a) + toDouble(b); - return result == Math.floor(result) ? (int) result : result; + a = unwrap(a); b = unwrap(b); + if (a instanceof List || b instanceof List) throw new RuntimeException("Cannot add arrays"); + if (a instanceof Integer && b instanceof Integer) return (Integer)a + (Integer)b; + + // Use BigDecimal for high precision addition + BigDecimal bdA = toBigDecimal(a); + BigDecimal bdB = toBigDecimal(b); + return bdA.add(bdB); } - public Object subtractNumbers(Object a, Object b) { - if (a instanceof Integer && b instanceof Integer) return (Integer) a - (Integer) b; - double result = toDouble(a) - toDouble(b); - return result == Math.floor(result) ? (int) result : result; + a = unwrap(a); b = unwrap(b); + if (a instanceof List || b instanceof List) throw new RuntimeException("Cannot operate on arrays"); + if (a instanceof Integer && b instanceof Integer) return (Integer)a - (Integer)b; + + // Use BigDecimal for high precision subtraction + BigDecimal bdA = toBigDecimal(a); + BigDecimal bdB = toBigDecimal(b); + return bdA.subtract(bdB); } - public Object multiplyNumbers(Object a, Object b) { - if (a instanceof Integer && b instanceof Integer) return (Integer) a * (Integer) b; - double result = toDouble(a) * toDouble(b); - return result == Math.floor(result) ? (int) result : result; + a = unwrap(a); b = unwrap(b); + if (a instanceof List || b instanceof List) throw new RuntimeException("Cannot operate on arrays"); + if (a instanceof Integer && b instanceof Integer) return (Integer)a * (Integer)b; + + // Use BigDecimal for high precision multiplication + BigDecimal bdA = toBigDecimal(a); + BigDecimal bdB = toBigDecimal(b); + return bdA.multiply(bdB); } - public Object divideNumbers(Object a, Object b) { - double result = toDouble(a) / toDouble(b); - return result == Math.floor(result) ? (int) result : result; + a = unwrap(a); b = unwrap(b); + if (a instanceof List || b instanceof List) throw new RuntimeException("Cannot operate on arrays"); + + // Use BigDecimal for high precision division + BigDecimal bdA = toBigDecimal(a); + BigDecimal bdB = toBigDecimal(b); + + if (bdB.compareTo(BigDecimal.ZERO) == 0) { + throw new RuntimeException("Division by zero"); + } + + // Use a fixed scale for division to prevent ArithmeticException + return bdA.divide(bdB, DECIMAL_SCALE, RoundingMode.HALF_UP); } - public Object modulusNumbers(Object a, Object b) { - if (a instanceof Integer && b instanceof Integer) { - int intB = (Integer) b; - if (intB == 0) throw new RuntimeException("Modulus by zero"); - return (Integer) a % intB; - } - - double da = toDouble(a); - double db = toDouble(b); - if (db == 0) throw new RuntimeException("Modulus by zero"); - - double result = da % db; - return result == Math.floor(result) ? (int) result : result; - } - - public double toDouble(Object val) { - if (val instanceof Integer) return ((Integer) val).doubleValue(); - if (val instanceof Float) return ((Float) val).doubleValue(); - if (val instanceof Double) return (Double) val; - if (val instanceof List) { - // For arrays, return their size - return ((List) val).size(); - } - throw new RuntimeException("Cannot convert to number: " + val); - } - - /** - * Negates a number value (unary minus operation) Handles different numeric types: Integer, - * Float, Double Also handles string conversion for numeric strings - */ - public Object negateNumber(Object operand) { - DebugSystem.debug( - "UNARY", - "Negating: " + operand + " (type: " + operand.getClass().getSimpleName() + ")"); - - if (operand instanceof Integer) { - int value = (Integer) operand; - return -value; - } else if (operand instanceof Float) { - float value = (Float) operand; - return -value; - } else if (operand instanceof Double) { - double value = (Double) operand; - return -value; - } else if (operand instanceof String) { - // Try to parse string as number and negate + a = unwrap(a); b = unwrap(b); + if (a instanceof List || b instanceof List) throw new RuntimeException("Cannot operate on arrays"); + // Modulus is less common for floats, fall back to double for simplicity + // as BigDecimal modulus is complex and rarely used in range-like contexts. + if (a instanceof Integer && b instanceof Integer) return (Integer)a % (Integer)b; + return toDouble(a) % toDouble(b); + } + public Object negateNumber(Object a) { + a = unwrap(a); + if (a instanceof List) throw new RuntimeException("Cannot operate on arrays"); + if (a instanceof Integer) return -(Integer)a; + + if (a instanceof BigDecimal) return ((BigDecimal) a).negate(); + return -toDouble(a); + } + + public double toDouble(Object o) { + o = unwrap(o); + if (o instanceof Integer) return ((Integer)o).doubleValue(); + if (o instanceof Long) return ((Long)o).doubleValue(); + if (o instanceof Float) return ((Float)o).doubleValue(); + if (o instanceof Double) return (Double)o; + if (o instanceof BigDecimal) return ((BigDecimal) o).doubleValue(); // NEW: Handle BigDecimal + if (o instanceof Boolean) return ((Boolean)o) ? 1.0 : 0.0; + if (o instanceof String) { try { - String str = (String) operand; - if (str.contains(".")) { - return -Double.parseDouble(str); - } else { - int intValue = Integer.parseInt(str); - return -intValue; - } + return Double.parseDouble((String)o); } catch (NumberFormatException e) { - throw new RuntimeException("Cannot negate non-numeric string: " + operand); + throw new RuntimeException("Cannot convert string '" + o + "' to number"); } - } else { - // Fallback: convert to double and negate + } + throw new RuntimeException("Cannot convert " + o + " to number"); + } + + // NEW: High precision conversion method + public BigDecimal toBigDecimal(Object o) { + o = unwrap(o); + if (o instanceof Integer || o instanceof Long) return new BigDecimal(o.toString()); + if (o instanceof Float || o instanceof Double) return new BigDecimal(o.toString()); + if (o instanceof BigDecimal) return (BigDecimal) o; + if (o instanceof Boolean) return ((Boolean)o) ? BigDecimal.ONE : BigDecimal.ZERO; + if (o instanceof String) { try { - double value = toDouble(operand); - // Return same type if possible, otherwise return as double - if (operand instanceof Integer) { - return (int) -value; - } else if (operand instanceof Float) { - return (float) -value; - } else { - return -value; + return new BigDecimal((String)o); + } catch (NumberFormatException e) { + throw new RuntimeException("Cannot convert string '" + o + "' to BigDecimal"); + } + } + throw new RuntimeException("Cannot convert " + o + " to BigDecimal"); + } + + public int compare(Object a, Object b) { + a = unwrap(a); b = unwrap(b); + if (a instanceof String || b instanceof String) return String.valueOf(a).compareTo(String.valueOf(b)); + + // Use BigDecimal comparison for high precision + if (a instanceof BigDecimal || b instanceof BigDecimal || + a instanceof Double || b instanceof Double || + a instanceof Float || b instanceof Float) { + + BigDecimal bdA = toBigDecimal(a); + BigDecimal bdB = toBigDecimal(b); + return bdA.compareTo(bdB); + } + + // Fallback to integer comparison if both are integers/longs + double valA = toDouble(a); double valB = toDouble(b); + return Double.compare(valA, valB); + } + + public Object convertType(Object value, String targetType) { + value = unwrap(value); + + // Convert from BigDecimal to target type + if (value instanceof BigDecimal) { + BigDecimal bd = (BigDecimal) value; + if (targetType.equals(INT.toString())) return bd.intValue(); + if (targetType.equals(FLOAT.toString())) return bd.doubleValue(); + if (targetType.equals(TEXT.toString())) { + // FIX: Use toPlainString() not toString() + bd = bd.stripTrailingZeros(); + return bd.toPlainString(); + } + } + + if (targetType.equals(INT.toString())) return (int) toDouble(value); + if (targetType.equals(FLOAT.toString())) return toDouble(value); + + // FIXED TEXT CONVERSION + if (targetType.equals(TEXT.toString())) { + if (value instanceof BigDecimal) { + // Already handled above, but keep for safety + BigDecimal bd = (BigDecimal) value; + bd = bd.stripTrailingZeros(); + return bd.toPlainString(); + } + if (value instanceof Double) { + // Handle Double to avoid scientific notation + Double d = (Double) value; + BigDecimal bd = new BigDecimal(d); + bd = bd.stripTrailingZeros(); + return bd.toPlainString(); + } + if (value instanceof Float) { + // Handle Float to avoid scientific notation + Float f = (Float) value; + BigDecimal bd = new BigDecimal(f); + bd = bd.stripTrailingZeros(); + return bd.toPlainString(); + } + return String.valueOf(value); + } + + if (targetType.equals(BOOL.toString())) { + if (value instanceof Boolean) return value; + if (value instanceof String) { + String strVal = ((String)value).toLowerCase().trim(); + if (strVal.equals("true")) return true; + if (strVal.equals("false")) return false; + try { + return Double.parseDouble(strVal) != 0.0; + } catch (NumberFormatException e) { + throw new RuntimeException("Cannot convert string '" + value + "' to boolean"); } - } catch (Exception e) { - throw new RuntimeException( - "Cannot negate value: " - + operand - + " (type: " - + operand.getClass().getSimpleName() - + ")"); } + return toDouble(value) != 0.0; } + + throw new RuntimeException("Cannot convert value '" + value + "' to type '" + targetType + "'"); } + + public String getConcreteType(Object value) { + if (value instanceof Integer) return INT.toString(); + if (value instanceof Long) return INT.toString(); + if (value instanceof String) return TEXT.toString(); + if (value instanceof Float || value instanceof Double) return FLOAT.toString(); + if (value instanceof BigDecimal) { + // Check if it's an integer BigDecimal + BigDecimal bd = (BigDecimal) value; + if (bd.scale() <= 0 || bd.stripTrailingZeros().scale() <= 0) { + return INT.toString(); // Integer BigDecimal + } + return FLOAT.toString(); // Fractional BigDecimal + } + if (value instanceof Boolean) return BOOL.toString(); + if (value instanceof List) return "list"; + if (value instanceof NaturalArray) return "list"; // Treat NaturalArray as list type + return "unknown"; + } + + public boolean validateType(String typeSig, Object value) { + String typeSigTrimmed = typeSig.trim(); + if (typeSigTrimmed.contains("|")) { + if (!isTypeStructurallyValid(typeSigTrimmed)) { + throw new RuntimeException("Union type contains illegal keywords. Only explicit types allowed."); + } + } + if (value instanceof TypedValue) { + TypedValue tv = (TypedValue) value; + return validateTypeInternal(typeSig, tv.value, tv.activeType); + } + String concreteType = getConcreteType(value); + return validateTypeInternal(typeSig, value, concreteType); + } + + private boolean validateTypeInternal(String typeSig, Object rawValue, String concreteType) { + if (typeSig == null) return true; + String type = typeSig.trim(); + + if (type.equals(ANY.toString())) return true; + + if (rawValue == null) return false; + + // 1. Unions + List unionParts = splitTopLevel(type, '|'); + if (unionParts.size() > 1) { + for (String part : unionParts) { + if (validateTypeInternal(part, rawValue, concreteType)) return true; + } + return false; + } + + // 2. Arrays - CHANGED: Check for [type] instead of type[] + if (type.startsWith("[") && type.endsWith("]")) { + if (!(rawValue instanceof List || rawValue instanceof NaturalArray)) return false; + + // Special case: empty brackets [] (dynamic array) accepts any array + if (type.equals("[]")) { + return true; // [] accepts any array type + } + + String baseType = type.substring(1, type.length() - 1); + + // For NaturalArray, just check the bounds/properties, not every element + if (rawValue instanceof NaturalArray) return true; + + List list = (List) rawValue; + for (Object item : list) { + if (!validateType(baseType, item)) return false; + } + return true; + } + + // 3. Groups/Tuples + if (type.startsWith("(") && type.endsWith(")")) { + String content = type.substring(1, type.length() - 1); + List tupleTypes = splitTopLevel(content, ','); + if (tupleTypes.size() == 1) return validateTypeInternal(tupleTypes.get(0), rawValue, concreteType); + if (!(rawValue instanceof List)) return false; + List list = (List) rawValue; + if (list.size() != tupleTypes.size()) return false; + for (int i = 0; i < tupleTypes.size(); i++) { + if (!validateType(tupleTypes.get(i), list.get(i))) return false; + } + return true; + } + + // 4. Primitives + return type.equals(concreteType) || checkPrimitiveMatch(type, rawValue); +} + +private boolean isTypeStructurallyValid(String typeSig) { + List unionParts = splitTopLevel(typeSig, '|'); + if (unionParts.size() > 1) { + for (String part : unionParts) if (!isTypeStructurallyValid(part)) return false; + return true; + } + String type = typeSig.trim(); + if (type.isEmpty()) return false; + + // CHANGED: Check for [type] instead of type[] + if (type.startsWith("[") && type.endsWith("]")) { + String inner = type.substring(1, type.length() - 1); + // Special case: [] is valid (dynamic array) + if (inner.isEmpty()) return true; + return isTypeStructurallyValid(inner); + } + + if (type.startsWith("(") && type.endsWith(")")) { + String content = type.substring(1, type.length() - 1); + List parts = splitTopLevel(content, ','); + for (String part : parts) if (!isTypeStructurallyValid(part)) return false; + return true; + } + + if (type.equals(INT.toString()) || type.equals(FLOAT.toString()) || + type.equals(TEXT.toString()) || type.equals(BOOL.toString()) || type.equals(ANY.toString())) { + return true; + } + if (Character.isUpperCase(type.charAt(0))) return true; + return false; } + +private boolean checkPrimitiveMatch(String type, Object rawValue) { + // Handle array types with [type] notation + if (type.startsWith("[") && type.endsWith("]")) { + // Special case: empty brackets [] (dynamic array) + if (type.equals("[]")) { + // [] accepts any array + return rawValue instanceof List || rawValue instanceof NaturalArray; + } + + // Regular [type] - for primitive matching, just check if it's an array + // The actual element type validation happens in validateTypeInternal + return rawValue instanceof List || rawValue instanceof NaturalArray; + } + + if (type == INT.toString()) return rawValue instanceof Integer || rawValue instanceof Long; + else if (type == TEXT.toString()) return rawValue instanceof String; + else if (type == FLOAT.toString()) return rawValue instanceof Float || rawValue instanceof Double || rawValue instanceof BigDecimal; + else if (type == BOOL.toString()) return rawValue instanceof Boolean; + return false; +} + + private List splitTopLevel(String input, char delimiter) { + List parts = new ArrayList(); + int parenDepth = 0; + StringBuilder current = new StringBuilder(); + for (char c : input.toCharArray()) { + if (c == '(') parenDepth++; + else if (c == ')') parenDepth--; + if (c == delimiter && parenDepth == 0) { + parts.add(current.toString().trim()); + current.setLength(0); + } else { + current.append(c); + } + } + parts.add(current.toString().trim()); + return parts; + } +} \ No newline at end of file diff --git a/src/main/java/cod/interpreter/TypedValue.java b/src/main/java/cod/interpreter/TypedValue.java new file mode 100644 index 00000000..fa799c26 --- /dev/null +++ b/src/main/java/cod/interpreter/TypedValue.java @@ -0,0 +1,26 @@ +// In TypedValue.java +package cod.interpreter; + +public class TypedValue { + + // The raw data being stored (e.g., Integer(5), String("hello"), or List) + public final Object value; + + // The specific type active in this instance (e.g., "int" or "text") + public final String activeType; + + // The full declared Union type signature (e.g., "int|text" or "(float,int)|bool") + public final String declaredType; + + public TypedValue(Object value, String activeType, String declaredType) { + this.value = value; + this.activeType = activeType; + this.declaredType = declaredType; + } + + // ADD THIS toString() METHOD BACK + @Override + public String toString() { + return String.valueOf(value); + } +} \ No newline at end of file From 8bec5ef140eb42c26ee5c43a7769c61d26bf9f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:28:47 +0800 Subject: [PATCH 35/54] Delete src/main/java/cod/interpreter/ExpressionEvaluator.java --- .../cod/interpreter/ExpressionEvaluator.java | 395 ------------------ 1 file changed, 395 deletions(-) delete mode 100644 src/main/java/cod/interpreter/ExpressionEvaluator.java diff --git a/src/main/java/cod/interpreter/ExpressionEvaluator.java b/src/main/java/cod/interpreter/ExpressionEvaluator.java deleted file mode 100644 index e4069409..00000000 --- a/src/main/java/cod/interpreter/ExpressionEvaluator.java +++ /dev/null @@ -1,395 +0,0 @@ -package cod.interpreter; - -import cod.ast.nodes.*; -import cod.ast.ASTFactory; -import cod.debug.DebugSystem; -import java.util.*; - -public class ExpressionEvaluator { - private TypeSystem typeSystem; - private Interpreter interpreter; - - public ExpressionEvaluator(TypeSystem typeSystem, Interpreter interpreter) { - this.typeSystem = typeSystem; - this.interpreter = interpreter; - } - - public Object evaluate(ExprNode expr, ObjectInstance obj, Map locals) { - DebugSystem.trace("EXPRESSIONS", "Evaluating: " + expr.getClass().getSimpleName()); - - // --- NEW: Handles 'if all:(A, B)' and 'if any: A, B' --- - if (expr instanceof BooleanChainNode) { - return evaluateBooleanChain((BooleanChainNode) expr, obj, locals); - } - // ... (UnaryNode, EqualityChainNode, TypeCastNode, ArrayNode, IndexAccessNode) ... - - if (expr instanceof UnaryNode) { - UnaryNode unary = (UnaryNode) expr; - Object operand = evaluate(unary.operand, obj, locals); - DebugSystem.debug("EXPRESSIONS", "Unary operation: " + unary.op + " " + operand); - - switch (unary.op) { - case "-": - return typeSystem.negateNumber(operand); - case "+": - return operand; - case "!": - return !isTruthy(operand); - default: - throw new RuntimeException("Unknown unary operator: " + unary.op); - } - } - - if (expr instanceof EqualityChainNode) { - return evaluateEqualityChain((EqualityChainNode) expr, obj, locals); - } - - if (expr instanceof TypeCastNode) { - TypeCastNode cast = (TypeCastNode) expr; - Object value = evaluate(cast.expression, obj, locals); - DebugSystem.debug("TYPECAST", "Casting " + value + " to " + cast.targetType); - return typeSystem.convertType(value, cast.targetType); - - } else if (expr instanceof ArrayNode) { - ArrayNode arrayNode = (ArrayNode) expr; - List array = new ArrayList(); - for (ExprNode elem : arrayNode.elements) { - array.add(evaluate(elem, obj, locals)); - } - DebugSystem.debug("ARRAYS", "Created array with " + array.size() + " elements"); - return array; - - } else if (expr instanceof IndexAccessNode) { - IndexAccessNode indexNode = (IndexAccessNode) expr; - Object arrayObj = evaluate(indexNode.array, obj, locals); - Object indexObj = evaluate(indexNode.index, obj, locals); - - if (arrayObj instanceof List && indexObj instanceof Integer) { - List list = (List) arrayObj; - int index = (Integer) indexObj; - - if (index >= 0 && index < list.size()) { - Object value = list.get(index); - DebugSystem.debug("ARRAYS", "Array access: [" + index + "] = " + value); - return value; - } else { - throw new RuntimeException( - "Array index out of bounds: " - + index - + " for array size " - + list.size()); - } - } else { - throw new RuntimeException( - "Invalid array access - array: " - + arrayObj.getClass() - + ", index: " - + indexObj.getClass()); - } - - } else if (expr instanceof BinaryOpNode) { - BinaryOpNode binOp = (BinaryOpNode) expr; - - boolean isForLoopStep = isForLoopStepEvaluation(binOp, obj, locals); - - if (isAssignmentOperator(binOp.op) && !isForLoopStep) { - throw new RuntimeException("Assignment operator '" + binOp.op + "' cannot be used in expressions - use statements instead"); - } - - Object left = evaluate(binOp.left, obj, locals); - Object right = evaluate(binOp.right, obj, locals); - DebugSystem.debug( - "EXPRESSIONS", "Binary operation: " + left + " " + binOp.op + " " + right); - - switch (binOp.op) { - case "+": - return (left instanceof String || right instanceof String) - ? String.valueOf(left) + right - : typeSystem.addNumbers(left, right); - case "-": - return typeSystem.subtractNumbers(left, right); - case "*": - return typeSystem.multiplyNumbers(left, right); - case "/": - return typeSystem.divideNumbers(left, right); - case "%": - return typeSystem.modulusNumbers(left, right); - case ">": - return typeSystem.compare(left, right) > 0; - case "<": - return typeSystem.compare(left, right) < 0; - case ">=": - return typeSystem.compare(left, right) >= 0; - case "<=": - return typeSystem.compare(left, right) <= 0; - case "==": - return left.equals(right); - case "!=": - return !left.equals(right); - case "=": - return right; - case "+=": - return typeSystem.addNumbers(left, right); - case "-=": - return typeSystem.subtractNumbers(left, right); - case "*=": - return typeSystem.multiplyNumbers(left, right); - case "/=": - return typeSystem.divideNumbers(left, right); - default: - throw new RuntimeException("Unknown operator: " + binOp.op); - } - } else if (expr instanceof MethodCallNode) { - MethodCallNode call = (MethodCallNode) expr; - - if (call.chainType != null && call.chainArguments != null) { - return evaluateConditionalChain(call, obj, locals); - } - - DebugSystem.debug("EXPR_METHOD_CALL", "=== EXPRESSION METHOD CALL ==="); - DebugSystem.debug("EXPR_METHOD_CALL", "call.name: " + call.name); - DebugSystem.debug("EXPR_METHOD_CALL", "call.qualifiedName: " + call.qualifiedName); - DebugSystem.debug("EXPR_METHOD_CALL", "call.slotNames: " + call.slotNames); - DebugSystem.debug("EXPR_METHOD_CALL", "call.arguments: " + call.arguments.size()); - for (int i = 0; i < call.arguments.size(); i++) { - DebugSystem.debug("EXPR_METHOD_CALL", " arg[" + i + "]: " + call.arguments.get(i).getClass().getSimpleName()); - } - - Object result = interpreter.evalMethodCall(call, obj, locals); - - if (call.slotNames != null && !call.slotNames.isEmpty() && result instanceof Map) { - Map slotReturns = (Map) result; - for (String slotName : call.slotNames) { - if (slotReturns.containsKey(slotName)) { - Object slotValue = slotReturns.get(slotName); - DebugSystem.debug( - "SLOTS", - "Slot '" + slotName + "' extracted in expression (read-only)"); - } - } - } - - return result; - } else if (expr.name != null) { - Object value = null; - if (locals.containsKey(expr.name)) { - value = locals.get(expr.name); - DebugSystem.trace("MEMORY", "Found local: " + expr.name + " = " + value); - } else if (interpreter.currentSlots != null - && interpreter.currentSlots.containsKey(expr.name)) { - value = interpreter.currentSlots.get(expr.name); - DebugSystem.trace("MEMORY", "Found slot: " + expr.name + " = " + value); - } else if (obj.fields.containsKey(expr.name)) { - value = obj.fields.get(expr.name); - DebugSystem.trace("MEMORY", "Found field: " + expr.name + " = " + value); - } else { - throw new RuntimeException("Undefined Variable: " + expr.name); - } - return value; - } else if (expr.value != null) { - DebugSystem.trace("EXPRESSIONS", "Literal value: " + expr.value); - if (expr.value instanceof String) { - String s = (String) expr.value; - if (s.startsWith("\"") && s.endsWith("\"") && s.length() >= 2) - s = s.substring(1, s.length() - 1); - return s; - } - return expr.value; - } - return null; - } - - private Object evaluateEqualityChain(EqualityChainNode chain, ObjectInstance obj, Map locals) { - - // --- NEW: Handle Array-based check (e.g., 'all scores >= 60') --- - Object leftObj = evaluate(chain.left, obj, locals); - - List targetValues; - - if (leftObj instanceof List) { - // Case 1: Array-based check (e.g., 'all scores >= 60') - targetValues = (List) leftObj; - } else { - // Case 2: Standard check (e.g., 'x == any[1, 2, 3]') or Reverse Check (e.g., 'any[1, 2, 3] == x') - // In both these cases, the "target" of the comparison is the single leftObj - targetValues = new ArrayList(); - targetValues.add(leftObj); - } - - boolean isAllChain = chain.isAllChain; - boolean result = isAllChain; - - DebugSystem.debug("EQUALITY_CHAIN", "Starting " + (isAllChain ? "all" : "any") + " chain with operator: " + chain.operator); - - // If it's an array check, the chain arguments must have a single value (e.g., 60) - // If it's a standard check, the targetValues has a single value (e.g., x) - - List comparisonValues = chain.chainArguments; - - if (targetValues.size() > 1 && comparisonValues.size() > 1) { - throw new RuntimeException("Ambiguous chain: Cannot compare array against array/list of values in an equality chain."); - } - - // --- NEW Logic for array iteration (Case 1) --- - if (targetValues.size() > 1) { - Object rightValue = comparisonValues.size() == 1 ? evaluate(comparisonValues.get(0), obj, locals) : null; - - for (Object targetValue : targetValues) { - boolean currentResult = compareValues(targetValue, chain.operator, rightValue); - - if (isAllChain) { - result = result && currentResult; - if (!result) { - DebugSystem.debug("EQUALITY_CHAIN", "ALL array chain short-circuited at false"); - break; - } - } else { - result = result || currentResult; - if (result) { - DebugSystem.debug("EQUALITY_CHAIN", "ANY array chain short-circuited at true"); - break; - } - } - } - - } else { - // --- Original Logic for single-value check (Case 2 and Reverse) --- - Object fixedLeftValue = targetValues.get(0); - - for (ExprNode chainArg : comparisonValues) { - Object rightValue = evaluate(chainArg, obj, locals); - boolean currentResult = compareValues(fixedLeftValue, chain.operator, rightValue); - - if (isAllChain) { - result = result && currentResult; - if (!result) { - DebugSystem.debug("EQUALITY_CHAIN", "ALL chain short-circuited at false"); - break; - } - } else { - result = result || currentResult; - if (result) { - DebugSystem.debug("EQUALITY_CHAIN", "ANY chain short-circuited at true"); - break; - } - } - } - } - - DebugSystem.debug("EQUALITY_CHAIN", "Equality chain result: " + result); - return result; - } - - // --- NEW: Comparison helper method to clean up chain logic --- - private boolean compareValues(Object leftValue, String operator, Object rightValue) { - switch (operator) { - case "==": - return leftValue.equals(rightValue); - case "!=": - return !leftValue.equals(rightValue); - case ">": - return typeSystem.compare(leftValue, rightValue) > 0; - case "<": - return typeSystem.compare(leftValue, rightValue) < 0; - case ">=": - return typeSystem.compare(leftValue, rightValue) >= 0; - case "<=": - return typeSystem.compare(leftValue, rightValue) <= 0; - default: - throw new RuntimeException("Unsupported operator in equality chain: " + operator); - } - } - - private Object evaluateBooleanChain(BooleanChainNode chain, ObjectInstance obj, Map locals) { - boolean isAll = chain.isAll; - boolean result = isAll; - - DebugSystem.debug("BOOL_CHAIN", "Starting " + (isAll ? "all" : "any") + " boolean chain"); - - if (isAll) { - result = true; - for (ExprNode e : chain.expressions) { - Object val = evaluate(e, obj, locals); - if (!isTruthy(val)) { - DebugSystem.debug("BOOL_CHAIN", "ALL chain short-circuited (found false)"); - result = false; - break; - } - } - } else { - result = false; - for (ExprNode e : chain.expressions) { - Object val = evaluate(e, obj, locals); - if (isTruthy(val)) { - DebugSystem.debug("BOOL_CHAIN", "ANY chain short-circuited (found true)"); - result = true; - break; - } - } - } - return result; - } - - private Object evaluateConditionalChain(MethodCallNode call, ObjectInstance obj, Map locals) { - boolean isAllChain = "all".equals(call.chainType); - boolean result = isAllChain; - - DebugSystem.debug("CHAIN", "Starting " + call.chainType + " chain for method: " + call.name); - - for (ExprNode chainArg : call.chainArguments) { - MethodCallNode singleCall = ASTFactory.createMethodCall(call.name, call.qualifiedName); - singleCall.arguments = new ArrayList(); - - boolean currentResult; - if (chainArg instanceof UnaryNode && "!".equals(((UnaryNode)chainArg).op)) { - UnaryNode unary = (UnaryNode) chainArg; - singleCall.arguments.add(unary.operand); - Object methodResult = interpreter.evalMethodCall(singleCall, obj, locals); - currentResult = !isTruthy(methodResult); - DebugSystem.debug("CHAIN", "Negated argument: !" + unary.operand + " = " + currentResult); - } else { - singleCall.arguments.add(chainArg); - Object methodResult = interpreter.evalMethodCall(singleCall, obj, locals); - currentResult = isTruthy(methodResult); - DebugSystem.debug("CHAIN", "Regular argument: " + chainArg + " = " + currentResult); - } - - if (isAllChain) { - result = result && currentResult; - if (!result) { - DebugSystem.debug("CHAIN", "ALL chain short-circuited at false"); - break; - } - } else { - result = result || currentResult; - if (result) { - DebugSystem.debug("CHAIN", "ANY chain short-circuited at true"); - break; - } - } - } - - DebugSystem.debug("CHAIN", "Conditional chain result: " + result + " for " + call.chainType); - return result; - } - - private boolean isTruthy(Object value) { - if (value == null) return false; - if (value instanceof Boolean) return (Boolean) value; - if (value instanceof Number) return ((Number) value).doubleValue() != 0.0; - if (value instanceof String) return !((String) value).isEmpty(); - if (value instanceof List) return !((List) value).isEmpty(); - if (value instanceof Map) return !((Map) value).isEmpty(); - return true; - } - - private boolean isAssignmentOperator(String op) { - return op.equals("=") || op.equals("+=") || op.equals("-=") || - op.equals("*=") || op.equals("/="); - } - - private boolean isForLoopStepEvaluation(BinaryOpNode binOp, ObjectInstance obj, Map locals) { - DebugSystem.debug("FOR_LOOP_STEP", "Checking if binary op is for loop step: " + binOp.op); - return true; - } -} \ No newline at end of file From d34d3dc3bdbd0d0f0230bfc8e0e3576202e754bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:29:01 +0800 Subject: [PATCH 36/54] Delete src/main/java/cod/interpreter/StatementEvaluator.java --- .../cod/interpreter/StatementEvaluator.java | 515 ------------------ 1 file changed, 515 deletions(-) delete mode 100644 src/main/java/cod/interpreter/StatementEvaluator.java diff --git a/src/main/java/cod/interpreter/StatementEvaluator.java b/src/main/java/cod/interpreter/StatementEvaluator.java deleted file mode 100644 index 66e55147..00000000 --- a/src/main/java/cod/interpreter/StatementEvaluator.java +++ /dev/null @@ -1,515 +0,0 @@ -package cod.interpreter; - -import cod.ast.nodes.*; -import cod.debug.DebugSystem; -import java.util.*; - -public class StatementEvaluator { - private Interpreter interpreter; - private ExpressionEvaluator exprEvaluator; - private IOHandler ioHandler; - private TypeSystem typeSystem; - - public StatementEvaluator(Interpreter interpreter, ExpressionEvaluator exprEvaluator, - IOHandler ioHandler, TypeSystem typeSystem) { - this.interpreter = interpreter; - this.exprEvaluator = exprEvaluator; - this.ioHandler = ioHandler; - this.typeSystem = typeSystem; - } - - public Object evalStmt(StatementNode stmt, ObjectInstance obj, Map locals, Map slotValues) { - DebugSystem.trace("INTERPRETER", "evalStmt: " + stmt.getClass().getSimpleName()); - - if (stmt instanceof SlotAssignmentNode) { - SlotAssignmentNode assign = (SlotAssignmentNode) stmt; - Object value = exprEvaluator.evaluate(assign.value, obj, locals); - String varName = assign.slotName; - - // --- NEW: Handle implicit returns --- - if ("return".equals(varName)) { - if (slotValues != null && !slotValues.isEmpty()) { - // Assign to the first declared slot - String firstSlot = slotValues.keySet().iterator().next(); - - // Validate Type - validateSlotType(firstSlot, value); - - Object oldValue = slotValues.get(firstSlot); - slotValues.put(firstSlot, value); - DebugSystem.slotUpdate(firstSlot, oldValue, value); - } - return value; - } - - // Check if slot exists - if (slotValues != null && slotValues.containsKey(varName)) { - // Enforce: If slot name is auto-generated (starts with digit), user cannot assign to it by name - if (Character.isDigit(varName.charAt(0))) { - throw new RuntimeException("Cannot assign to unnamed slot '" + varName + "' by name. Use positional assignment."); - } - - // Validate Type - validateSlotType(varName, value); - - Object oldValue = slotValues.get(varName); - slotValues.put(varName, value); - DebugSystem.slotUpdate(varName, oldValue, value); - } else { - // CHANGED: Warn -> Exception - throw new RuntimeException("Assignment to '" + varName + "' failed: Slot is not declared in method signature."); - } - return value; - - } else if (stmt instanceof MultipleSlotAssignmentNode) { - MultipleSlotAssignmentNode multiAssign = (MultipleSlotAssignmentNode) stmt; - - // Validate assignment count matches declared slots - List declaredSlots = new ArrayList(); - if (slotValues != null) { - // Sort keys if they look like indices "0", "1" to ensure positional correctness - List keys = new ArrayList<>(slotValues.keySet()); - Collections.sort(keys, new Comparator() { - @Override - public int compare(String o1, String o2) { - if (Character.isDigit(o1.charAt(0)) && Character.isDigit(o2.charAt(0))) { - try { - return Integer.valueOf(o1).compareTo(Integer.valueOf(o2)); - } catch (NumberFormatException e) {} - } - return o1.compareTo(o2); - } - }); - declaredSlots.addAll(keys); - } - - if (multiAssign.assignments.size() > declaredSlots.size()) { - throw new RuntimeException("Too many return assignments: declared " + - declaredSlots.size() + " slots but assigned " + - multiAssign.assignments.size() + " values"); - } - - Object lastValue = null; - int slotIndex = 0; - - for (SlotAssignmentNode assign : multiAssign.assignments) { - Object value = exprEvaluator.evaluate(assign.value, obj, locals); - String targetSlotName = null; - - if (assign.slotName != null) { - // Named assignment - targetSlotName = assign.slotName; - } else { - // Positional assignment - if (slotIndex < declaredSlots.size()) { - targetSlotName = declaredSlots.get(slotIndex); - } - } - - if (targetSlotName != null && slotValues.containsKey(targetSlotName)) { - // Enforce restriction: If doing Named assignment to Unnamed slot - if (assign.slotName != null && Character.isDigit(targetSlotName.charAt(0))) { - throw new RuntimeException("Cannot use named assignment '" + assign.slotName + "' for an unnamed slot."); - } - - // Validate Type - validateSlotType(targetSlotName, value); - - Object oldValue = slotValues.get(targetSlotName); - slotValues.put(targetSlotName, value); - DebugSystem.slotUpdate(targetSlotName, oldValue, value); - } else { - throw new RuntimeException("Slot '" + (targetSlotName != null ? targetSlotName : "index " + slotIndex) + "' not found."); - } - - lastValue = value; - slotIndex++; - } - - return lastValue; - - } else if (stmt instanceof InputNode) { - // Handle input: name = (type) input - InputNode input = (InputNode) stmt; - Object inputValue = ioHandler.readInput(input.targetType); - - if (slotValues != null && slotValues.containsKey(input.variableName)) { - throw new RuntimeException("Cannot assign to slot '" + input.variableName + "' using '=' (from input). Use '~> " + input.variableName + " ...' syntax instead."); - } else { - obj.fields.put(input.variableName, inputValue); - DebugSystem.fieldUpdate(input.variableName, inputValue); - } - locals.put(input.variableName, inputValue); - return inputValue; - - } else if (stmt instanceof AssignmentNode) { - AssignmentNode assignment = (AssignmentNode) stmt; - Object value = exprEvaluator.evaluate(assignment.right, obj, locals); - - if (assignment.right instanceof MethodCallNode) { - MethodCallNode methodCall = (MethodCallNode) assignment.right; - if (methodCall.slotNames != null && !methodCall.slotNames.isEmpty() && value instanceof Map) { - Map slotReturns = (Map) value; - String slotName = methodCall.slotNames.get(0); - - // Handle auto-numbered slots in calls: [0]:method() - if (!slotReturns.containsKey(slotName) && slotReturns.containsKey("0")) { - // If user asked for [name] but we have [0], checks fail unless mapped. - // But per requirements, user should use [0] if unnamed. - } - - if (slotReturns.containsKey(slotName)) { - value = slotReturns.get(slotName); - } - } - } - - if (assignment.left instanceof IndexAccessNode) { - IndexAccessNode indexAccess = (IndexAccessNode) assignment.left; - Object arrayObj = exprEvaluator.evaluate(indexAccess.array, obj, locals); - Object indexObj = exprEvaluator.evaluate(indexAccess.index, obj, locals); - - if (arrayObj instanceof List && indexObj instanceof Integer) { - List list = (List) arrayObj; - int index = (Integer) indexObj; - - if (index >= 0 && index < list.size()) { - list.set(index, value); - } else { - throw new RuntimeException("Array index out of bounds: " + index + " for array size " + list.size()); - } - } - } else if (assignment.left instanceof ExprNode) { - ExprNode target = (ExprNode) assignment.left; - if (target.name != null) { - String varName = target.name; - - if (slotValues != null && slotValues.containsKey(varName)) { - throw new RuntimeException("Cannot assign to slot '" + varName + "' using '='. Use '~ " + varName + " ...' syntax instead."); - } else if (locals.containsKey(varName)) { - locals.put(varName, value); - } else { - obj.fields.put(varName, value); - } - if (locals.containsKey(varName)) locals.put(varName, value); - } - } - - return value; - - } else if (stmt instanceof FieldNode) { - FieldNode f = (FieldNode) stmt; - Object val = f.value != null ? exprEvaluator.evaluate(f.value, obj, locals) : null; - - if (slotValues != null && slotValues.containsKey(f.name)) { - throw new RuntimeException("Cannot assign to slot '" + f.name + "' using '=' (in field declaration). Use '~> " + f.name + " ...' syntax instead."); - } else { - obj.fields.put(f.name, val); - } - return val; - - } else if (stmt instanceof VarNode) { - VarNode var = (VarNode) stmt; - Object val = var.value != null ? exprEvaluator.evaluate(var.value, obj, locals) : null; - - if (slotValues != null && slotValues.containsKey(var.name)) { - throw new RuntimeException("Cannot declare variable '" + var.name + "' because it conflicts with a return slot. Use '~> " + var.name + " ...' to assign to the slot."); - } - - locals.put(var.name, val); - return val; - - } else if (stmt instanceof OutputNode) { - OutputNode output = (OutputNode) stmt; - Object lastVal = null; - - for (ExprNode arg : output.arguments) { - if (arg instanceof MethodCallNode) { - MethodCallNode methodCall = (MethodCallNode) arg; - Object result = interpreter.evalMethodCall(methodCall, obj, locals); - - if (result instanceof Map) { - Map slotReturns = (Map) result; - - if (output.varName != null) { - lastVal = slotReturns.get(output.varName); - } else { - if (methodCall.slotNames != null && !methodCall.slotNames.isEmpty()) { - if (methodCall.slotNames.size() == 1) { - lastVal = slotReturns.get(methodCall.slotNames.get(0)); - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < methodCall.slotNames.size(); i++) { - if (i > 0) sb.append(", "); - String slotName = methodCall.slotNames.get(i); - Object value = slotReturns.get(slotName); - sb.append(value != null ? value.toString() : "null"); - } - lastVal = sb.toString(); - } - } else { - if (slotReturns.size() == 1) { - lastVal = slotReturns.values().iterator().next(); - } else { - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (Object value : slotReturns.values()) { - if (!first) sb.append(", "); - sb.append(value != null ? value.toString() : "null"); - first = false; - } - lastVal = sb.toString(); - } - } - } - } else { - lastVal = result; - } - } else { - lastVal = exprEvaluator.evaluate(arg, obj, locals); - } - } - - ioHandler.output(lastVal); - return lastVal; - - } else if (stmt instanceof IfNode) { - IfNode ifn = (IfNode) stmt; - boolean test = Boolean.TRUE.equals(exprEvaluator.evaluate(ifn.condition, obj, locals)); - - Set previousSlotsInPath = new HashSet<>(interpreter.slotsInCurrentPath); - - List branch = test ? ifn.thenBlock.statements : ifn.elseBlock.statements; - for (StatementNode s : branch) { - evalStmt(s, obj, locals, slotValues); - if (!interpreter.slotsInCurrentPath.isEmpty() && interpreter.shouldReturnEarly(slotValues)) { - break; - } - } - - interpreter.slotsInCurrentPath = previousSlotsInPath; - return null; - - } else if (stmt instanceof ForNode) { - ForNode f = (ForNode) stmt; - RangeNode range = f.range; - String iteratorName = f.iterator; - - Object startObj = exprEvaluator.evaluate(range.start, obj, locals); - Object endObj = exprEvaluator.evaluate(range.end, obj, locals); - double start = typeSystem.toDouble(startObj); - double end = typeSystem.toDouble(endObj); - - Set previousSlotsInPath = new HashSet<>(interpreter.slotsInCurrentPath); - - boolean isTransformativeStep = isTransformativeStep(range.step, iteratorName); - double stepValue = 1.0; - if (!isTransformativeStep) { - if (range.step == null) { - stepValue = (start > end) ? -1.0 : 1.0; - } else { - Map tempLocals = new HashMap<>(locals); - tempLocals.put(iteratorName, start); - Object stepObj = exprEvaluator.evaluate(range.step, obj, tempLocals); - stepValue = typeSystem.toDouble(stepObj); - } - - if (stepValue == 0) { - throw new RuntimeException("Step cannot be zero in for loop."); - } - } - - Object originalValue = null; - boolean existedBefore = locals.containsKey(iteratorName); - if (existedBefore) { - originalValue = locals.get(iteratorName); - } - - double current = start; - locals.put(iteratorName, (int) current); - - try { - while(true) { - boolean shouldTerminate; - double effectiveStepDirection = isTransformativeStep ? (end >= start ? 1.0 : -1.0) : stepValue; - - if (effectiveStepDirection > 0) { - shouldTerminate = current > end; - } else { - shouldTerminate = current < end; - } - - if (shouldTerminate) break; - - for (StatementNode s : f.body.statements) { - evalStmt(s, obj, locals, slotValues); - if (!interpreter.slotsInCurrentPath.isEmpty() && interpreter.shouldReturnEarly(slotValues)) { - break; - } - } - if (!interpreter.slotsInCurrentPath.isEmpty() && interpreter.shouldReturnEarly(slotValues)) { - break; - } - - if (isTransformativeStep) { - Map tempLocals = new HashMap<>(locals); - tempLocals.put(iteratorName, current); - Object stepObj = exprEvaluator.evaluate(range.step, obj, tempLocals); - double newValue = typeSystem.toDouble(stepObj); - if (newValue == current && current != end) { - throw new RuntimeException("Loop step expression resulted in no change, causing infinite loop"); - } - current = newValue; - } else { - current += stepValue; - } - locals.put(iteratorName, (int) current); - } - - } finally { - if (existedBefore) { - locals.put(iteratorName, originalValue); - } else { - locals.remove(iteratorName); - } - } - - interpreter.slotsInCurrentPath = previousSlotsInPath; - return null; - - } else if (stmt instanceof MethodCallNode) { - MethodCallNode call = (MethodCallNode) stmt; - Object result = interpreter.evalMethodCall(call, obj, locals); - - if (call.slotNames != null && !call.slotNames.isEmpty() && result instanceof Map) { - Map slotReturns = (Map) result; - - for (String slotName : call.slotNames) { - if (slotReturns.containsKey(slotName)) { - Object slotValue = slotReturns.get(slotName); - if (slotValues != null && slotValues.containsKey(slotName)) { - validateSlotType(slotName, slotValue); // Validate Type - Object oldValue = slotValues.get(slotName); - slotValues.put(slotName, slotValue); - DebugSystem.slotUpdate(slotName, oldValue, slotValue); - } - } - } - } - return result; - - } else if (stmt instanceof ReturnSlotAssignmentNode) { - ReturnSlotAssignmentNode assignment = (ReturnSlotAssignmentNode) stmt; - Object result = interpreter.evalMethodCall(assignment.methodCall, obj, locals); - - if (result instanceof Map) { - Map slotReturns = (Map) result; - - for (int i = 0; i < assignment.variableNames.size(); i++) { - String varName = assignment.variableNames.get(i); - String slotName = assignment.methodCall.slotNames.get(i); - - if (slotReturns.containsKey(slotName)) { - Object slotValue = slotReturns.get(slotName); - - if (slotValues != null && slotValues.containsKey(varName)) { - throw new RuntimeException("Cannot assign to variable '" + varName + "' because it conflicts with a return slot."); - } - - locals.put(varName, slotValue); - } else { - // Handle named assignment to unnamed slot index - if (slotReturns.containsKey("0") && Character.isDigit(slotName.charAt(0))) { - // Fallback? No, user must call by index if slots are unnamed - } - // CHANGED: Warn -> Exception - throw new RuntimeException("Runtime Error: Slot '" + slotName + "' requested but not found in method return values."); - } - } - } - return result; - - } else if (stmt instanceof ExprNode) { - return exprEvaluator.evaluate((ExprNode) stmt, obj, locals); - } - - return null; - } - - // --- VALIDATION HELPER --- - private void validateSlotType(String slotName, Object value) { - if (interpreter.currentSlotTypes == null || !interpreter.currentSlotTypes.containsKey(slotName)) { - return; // Should not happen if logic is correct - } - - String expectedType = interpreter.currentSlotTypes.get(slotName); - if (value == null) return; // Null allowed? - - boolean isValid = false; - if (expectedType.equals("int")) { - isValid = value instanceof Integer; - } else if (expectedType.equals("float")) { - isValid = value instanceof Float || value instanceof Double; - } else if (expectedType.equals("string")) { - isValid = value instanceof String; - } else if (expectedType.equals("bool")) { - isValid = value instanceof Boolean; - } else { - // For custom class types, we might check instance type name - // Since we don't have full class metadata here easily, we might relax or check map - if (value instanceof ObjectInstance) { - isValid = ((ObjectInstance)value).type.name.equals(expectedType); - } else { - isValid = true; // Allow custom types for now if not primitive - } - } - - if (!isValid) { - throw new RuntimeException("Type mismatch for slot '" + slotName + - "'. Expected " + expectedType + - " but got " + value.getClass().getSimpleName()); - } - } - - // --- Helper Methods --- - - private boolean isTransformativeStep(ExprNode stepExpr, String iterator) { - if (stepExpr == null) return false; - if (stepExpr instanceof BinaryOpNode) { - BinaryOpNode binOp = (BinaryOpNode) stepExpr; - if (isAssignmentOperator(binOp.op)) { - return isIterator(binOp.left, iterator); - } else { - return containsIteratorVariable(binOp.left, iterator) || - containsIteratorVariable(binOp.right, iterator); - } - } else if (stepExpr instanceof UnaryNode) { - return containsIteratorVariable(((UnaryNode)stepExpr).operand, iterator); - } else if (stepExpr.name != null) { - return stepExpr.name.equals(iterator); - } - return false; - } - - private boolean containsIteratorVariable(ExprNode stepExpr, String iterator) { - if (stepExpr == null) return false; - if (stepExpr instanceof BinaryOpNode) { - BinaryOpNode binOp = (BinaryOpNode) stepExpr; - return containsIteratorVariable(binOp.left, iterator) || containsIteratorVariable(binOp.right, iterator); - } else if (stepExpr instanceof UnaryNode) { - return containsIteratorVariable(((UnaryNode)stepExpr).operand, iterator); - } else if (stepExpr.name != null) { - return stepExpr.name.equals(iterator); - } - return false; - } - - private boolean isIterator(ExprNode expr, String iterator) { - return expr != null && expr.name != null && expr.name.equals(iterator); - } - - private boolean isAssignmentOperator(String op) { - return op.equals("=") || op.equals("+=") || op.equals("-=") || - op.equals("*=") || op.equals("/="); - } -} \ No newline at end of file From 4ef80b21591da1e433359735f809fb8dbba6f216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:29:36 +0800 Subject: [PATCH 37/54] Add files via upload --- src/main/java/cod/runner/BaseRunner.java | 441 ++++++++++-------- src/main/java/cod/runner/CoderiveREPL.java | 149 ++++-- src/main/java/cod/runner/CommandRunner.java | 181 +++---- src/main/java/cod/runner/CompilerRunner.java | 300 ++++++++---- .../java/cod/runner/InterpreterRunner.java | 201 ++++++-- src/main/java/cod/runner/PrinterRunner.java | 245 ++++++++++ 6 files changed, 1043 insertions(+), 474 deletions(-) create mode 100644 src/main/java/cod/runner/PrinterRunner.java diff --git a/src/main/java/cod/runner/BaseRunner.java b/src/main/java/cod/runner/BaseRunner.java index 498886d0..0d6766eb 100644 --- a/src/main/java/cod/runner/BaseRunner.java +++ b/src/main/java/cod/runner/BaseRunner.java @@ -1,40 +1,17 @@ +// BaseRunner.java package cod.runner; -import cod.ast.*; import cod.ast.nodes.*; import cod.debug.DebugSystem; -import cod.ast.ASTPrinter; import java.io.*; import java.util.List; -// ANTLR-specific imports -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.RecognitionException; -import org.antlr.v4.runtime.BaseErrorListener; -import org.antlr.v4.runtime.Recognizer; - -// Manual-specific imports -import cod.ast.ManualCoderiveLexer; -import cod.ast.ManualCoderiveParser; - -// Linter import -import cod.debug.Linter; +import cod.lexer.MainLexer; +import cod.parser.MainParser; public abstract class BaseRunner { - - // Enum for parser mode - public enum ParserMode { - ANTLR, - MANUAL - } - // Configuration class for runner options - now with builder pattern public static class RunnerConfig { - public ParserMode parserMode = ParserMode.MANUAL; - public boolean printAST = false; - public boolean enableLinting = true; - public boolean stopOnLintError = false; public String inputFilename; public String outputFilename; public DebugSystem.Level debugLevel = DebugSystem.Level.INFO; @@ -43,27 +20,6 @@ public RunnerConfig(String inputFilename) { this.inputFilename = inputFilename; } - // Builder-style methods for fluent configuration - public RunnerConfig withParserMode(ParserMode mode) { - this.parserMode = mode; - return this; - } - - public RunnerConfig withPrintAST(boolean printAST) { - this.printAST = printAST; - return this; - } - - public RunnerConfig withLinting(boolean enableLinting) { - this.enableLinting = enableLinting; - return this; - } - - public RunnerConfig withStopOnLintError(boolean stopOnLintError) { - this.stopOnLintError = stopOnLintError; - return this; - } - public RunnerConfig withOutputFilename(String outputFilename) { this.outputFilename = outputFilename; return this; @@ -75,218 +31,315 @@ public RunnerConfig withDebugLevel(DebugSystem.Level debugLevel) { } } - // Configuration interface for anonymous inner class style public interface Configuration { void configure(RunnerConfig config); } protected static final String LOG_TAG = "RUNNER"; - /** - * Common method to parse a source file using either ANTLR or manual parser - */ - protected ProgramNode parseSourceFile(String filename, ParserMode mode) throws Exception { - switch (mode) { - case ANTLR: - return parseWithAntlr(filename); - case MANUAL: - return parseWithManual(filename); - default: - throw new IllegalArgumentException("Unknown parser mode: " + mode); - } - } - - /** - * Parse using ANTLR parser - */ - private ProgramNode parseWithAntlr(String filename) throws Exception { - DebugSystem.debug(LOG_TAG, "Loading source file for ANTLR: " + filename); - InputStream is = new FileInputStream(filename); - - ANTLRInputStream input = new ANTLRInputStream(is); - CoderiveLexer lexer = new CoderiveLexer(input); - CommonTokenStream tokens = new CommonTokenStream(lexer); - CoderiveParser parser = new CoderiveParser(tokens); - - parser.removeErrorListeners(); - parser.addErrorListener(new BaseErrorListener() { - @Override - public void syntaxError(Recognizer recognizer, Object offendingSymbol, - int line, int charPositionInLine, String msg, - RecognitionException e) { - String error = "Syntax error at line " + line + ":" + charPositionInLine + " - " + msg; - DebugSystem.error("PARSER", error); - throw new RuntimeException(error); - } - }); - - DebugSystem.debug("PARSER", "Building ANTLR parse tree..."); - CoderiveParser.ProgramContext programContext = parser.program(); - DebugSystem.debug("PARSER", "ANTLR parse tree built successfully"); - - ASTBuilder builder = new ASTBuilder(); - ProgramNode ast = builder.build(programContext); - - return ast; - } - - /** - * Parse using manual parser - */ - private ProgramNode parseWithManual(String filename) throws Exception { - DebugSystem.debug(LOG_TAG, "Loading source file for Manual Parser: " + filename); + public ProgramNode parse(String filename) throws Exception { + DebugSystem.debug(LOG_TAG, "Loading source file: " + filename); InputStream is = new FileInputStream(filename); String sourceCode = readFileToString(is); + DebugSystem.debug(LOG_TAG, "Source length: " + sourceCode.length() + " chars"); - DebugSystem.debug("PARSER", "Tokenizing with ManualLexer..."); - ManualCoderiveLexer lexer = new ManualCoderiveLexer(sourceCode); - List tokens = lexer.tokenize(); + DebugSystem.debug("PARSER", "Tokenizing..."); + MainLexer lexer = new MainLexer(sourceCode); + List tokens = lexer.tokenize(); + DebugSystem.debug("PARSER", "Generated " + tokens.size() + " tokens"); - DebugSystem.debug("PARSER", "Parsing with ManualParser..."); - ManualCoderiveParser parser = new ManualCoderiveParser(tokens); + DebugSystem.debug("PARSER", "Parsing..."); + MainParser parser = new MainParser(tokens); ProgramNode ast = parser.parseProgram(); - DebugSystem.debug("PARSER", "Manual parsing completed successfully"); + DebugSystem.debug("PARSER", "Parsing completed successfully"); return ast; } - /** - * Common file reading utility - */ protected String readFileToString(InputStream is) throws Exception { java.util.Scanner scanner = new java.util.Scanner(is).useDelimiter("\\A"); return scanner.hasNext() ? scanner.next() : ""; } - /** - * Common debug system configuration - */ - protected void configureDebugSystem(DebugSystem.Level level) { - DebugSystem.setLevel(level); - DebugSystem.enableCategory("BYTECODE"); - DebugSystem.enableCategory("MTOT"); - DebugSystem.enableCategory(LOG_TAG); - DebugSystem.enableCategory("PARSER"); - DebugSystem.enableCategory("INTERPRETER"); - DebugSystem.enableCategory("AST"); - DebugSystem.setShowTimestamp(true); - } - -/** - * Print AST if enabled in config with proper output synchronization - */ -protected void printASTIfEnabled(ProgramNode ast, RunnerConfig config) { - if (config.printAST) { - // Ensure any pending stderr output is flushed before printing AST to stdout - System.err.flush(); - - DebugSystem.info("AST", "Printing Abstract Syntax Tree:"); - ASTPrinter.print(ast); - - // Flush stdout after AST printing - System.out.flush(); - - DebugSystem.debug("AST", "AST printing completed"); - } + protected void configureDebugSystem(DebugSystem.Level level) { + DebugSystem.setLevel(level); + DebugSystem.enableCategory("BYTECODE"); + DebugSystem.enableCategory("MTOT"); + DebugSystem.enableCategory(LOG_TAG); + DebugSystem.enableCategory("PARSER"); + DebugSystem.enableCategory("INTERPRETER"); + DebugSystem.enableCategory("AST"); + DebugSystem.enableCategory("PERF"); + DebugSystem.setShowTimestamp(true); + DebugSystem.info(LOG_TAG, "DebugSystem configured to level: " + level); } -/** - * Perform linting if enabled in config - */ -protected boolean performLinting(ProgramNode ast, RunnerConfig config) { - if (!config.enableLinting) { - DebugSystem.debug("LINTER", "Linting disabled by configuration"); - return true; - } - - DebugSystem.startTimer("linting"); - Linter linter = new Linter(); - List warnings = linter.lint(ast); - DebugSystem.stopTimer("linting"); - - // Print warnings immediately and completely - Linter.WarningUtils.printWarnings(warnings); - - // Force complete output synchronization - System.out.flush(); - System.err.flush(); - - if (!warnings.isEmpty() && config.stopOnLintError) { - DebugSystem.error(LOG_TAG, "Execution stopped due to lint errors."); - return false; - } - - return true; -} - - /** - * Common method to extract filename from arguments - */ protected String extractFilenameFromArgs(String[] args, String defaultFilename) { for (String arg : args) { if (!arg.startsWith("--") && !arg.equals("-o")) { + DebugSystem.debug(LOG_TAG, "Extracted filename from args: " + arg); return arg; } } + DebugSystem.debug(LOG_TAG, "Using default filename: " + defaultFilename); return defaultFilename; } - /** - * Common method to process command line arguments and create configuration - * Now supports Configuration callback - */ protected RunnerConfig processCommandLineArgs(String[] args, String defaultInputFilename, Configuration configCallback) { + DebugSystem.debug(LOG_TAG, "Processing command line args, count: " + args.length); RunnerConfig config = new RunnerConfig(defaultInputFilename); - // Apply command line arguments first for (int i = 0; i < args.length; i++) { String arg = args[i]; - if ("--antlr".equals(arg)) { - config.parserMode = ParserMode.ANTLR; - } else if ("--manual".equals(arg)) { - config.parserMode = ParserMode.MANUAL; - } else if ("--print-ast".equals(arg)) { - config.printAST = true; - } else if ("--no-lint".equals(arg)) { - config.enableLinting = false; - } else if ("--stop-on-lint".equals(arg)) { - config.stopOnLintError = true; - } else if ("--debug".equals(arg)) { + if ("--debug".equals(arg)) { config.debugLevel = DebugSystem.Level.DEBUG; + DebugSystem.debug(LOG_TAG, "Set debug level to DEBUG"); } else if ("--trace".equals(arg)) { config.debugLevel = DebugSystem.Level.TRACE; + DebugSystem.trace(LOG_TAG, "Set debug level to TRACE"); } else if ("-o".equals(arg)) { if (i + 1 < args.length) { config.outputFilename = args[i + 1]; i++; + DebugSystem.debug(LOG_TAG, "Set output filename: " + config.outputFilename); } else { System.err.println("Error: -o option requires an output filename."); + DebugSystem.error(LOG_TAG, "-o option missing filename"); } } } - // Extract filename if not already set by -o processing if (config.inputFilename == null) { config.inputFilename = extractFilenameFromArgs(args, defaultInputFilename); } - // Apply configuration callback if provided if (configCallback != null) { configCallback.configure(config); } + DebugSystem.debug(LOG_TAG, "Config: input=" + config.inputFilename + + ", output=" + config.outputFilename + ", level=" + config.debugLevel); + return config; } - // Overloaded version for backward compatibility protected RunnerConfig processCommandLineArgs(String[] args, String defaultInputFilename) { return processCommandLineArgs(args, defaultInputFilename, null); } - /** - * Abstract method to be implemented by specific runners - */ + // ==================== CONSTANT FOLDING INTEGRATION ==================== + + protected T optimizeAST(T ast, boolean enableOptimization) { + if (!enableOptimization) { + DebugSystem.debug(LOG_TAG, "Skipping constant folding (disabled)"); + return ast; + } + + DebugSystem.debug(LOG_TAG, "Starting constant folding optimization..."); + DebugSystem.startTimer("constant_folding"); + + try { + Class optimizerClass = Class.forName("cod.ast.Optimizer"); + java.lang.reflect.Method foldMethod = optimizerClass.getMethod("foldConstants", ASTNode.class); + + @SuppressWarnings("unchecked") + T optimized = (T) foldMethod.invoke(null, ast); + + DebugSystem.stopTimer("constant_folding"); + long duration = DebugSystem.getTimerDuration("constant_folding"); + + DebugSystem.info(LOG_TAG, "Constant folding completed in " + duration + " ms"); + + if (DebugSystem.getLevel().compareTo(DebugSystem.Level.DEBUG) >= 0) { + printOptimizationDebugInfo(ast, optimized); + } + + return optimized; + + } catch (ClassNotFoundException e) { + DebugSystem.warn(LOG_TAG, "Optimizer class not found. Constant folding disabled."); + DebugSystem.warn(LOG_TAG, "Make sure Optimizer.java is in the classpath."); + return ast; + } catch (NoSuchMethodException e) { + DebugSystem.warn(LOG_TAG, "Optimizer.foldConstants method not found."); + return ast; + } catch (Exception e) { + DebugSystem.error(LOG_TAG, "Constant folding failed: " + e.getMessage()); + if (DebugSystem.getLevel().compareTo(DebugSystem.Level.DEBUG) >= 0) { + e.printStackTrace(); + } + return ast; + } + } + + protected T optimizeAST(T ast, boolean constantFolding, boolean otherOptimizations) { + if (!constantFolding && !otherOptimizations) { + return ast; + } + + DebugSystem.debug(LOG_TAG, "Starting optimizations..."); + DebugSystem.startTimer("optimizations"); + + T result = ast; + + if (constantFolding) { + result = optimizeAST(result, true); + } + + if (otherOptimizations) { + DebugSystem.debug(LOG_TAG, "Other optimizations requested but not implemented yet"); + } + + DebugSystem.stopTimer("optimizations"); + DebugSystem.info(LOG_TAG, "All optimizations completed in " + + DebugSystem.getTimerDuration("optimizations") + " ms"); + + return result; + } + + private void printOptimizationDebugInfo(ASTNode original, ASTNode optimized) { + if (original == optimized) { + DebugSystem.debug(LOG_TAG, "No changes made by constant folding"); + return; + } + + DebugSystem.debug(LOG_TAG, "AST modified by constant folding"); + + int originalEstimate = estimateNodeCount(original); + int optimizedEstimate = estimateNodeCount(optimized); + + if (optimizedEstimate < originalEstimate) { + int reduction = ((originalEstimate - optimizedEstimate) * 100) / originalEstimate; + DebugSystem.debug(LOG_TAG, "Estimated size reduction: " + reduction + "%"); + DebugSystem.debug(LOG_TAG, "Original: ~" + originalEstimate + " nodes"); + DebugSystem.debug(LOG_TAG, "Optimized: ~" + optimizedEstimate + " nodes"); + } + + try { + Class optimizerClass = Class.forName("cod.ast.Optimizer"); + java.lang.reflect.Method getStatsMethod = optimizerClass.getMethod("getStats"); + Object stats = getStatsMethod.invoke(null); + + if (stats != null) { + Class statsClass = stats.getClass(); + java.lang.reflect.Method getTotalMethod = statsClass.getMethod("getTotalOptimizations"); + Integer totalOpts = (Integer) getTotalMethod.invoke(stats); + + if (totalOpts != null && totalOpts > 0) { + DebugSystem.debug(LOG_TAG, "Total optimizations applied: " + totalOpts); + } + } + } catch (Exception e) { + // Ignore + } + } + + private int estimateNodeCount(ASTNode node) { + if (node == null) return 0; + + int count = 1; + + if (node instanceof ProgramNode) { + ProgramNode prog = (ProgramNode) node; + if (prog.unit != null) count += estimateNodeCount(prog.unit); + } else if (node instanceof UnitNode) { + UnitNode unit = (UnitNode) node; + if (unit.imports != null) count += estimateNodeCount(unit.imports); + for (TypeNode type : unit.types) { + count += estimateNodeCount(type); + } + } else if (node instanceof TypeNode) { + TypeNode type = (TypeNode) node; + for (FieldNode field : type.fields) { + count += estimateNodeCount(field); + } + for (MethodNode method : type.methods) { + count += estimateNodeCount(method); + } + for (StmtNode stmt : type.statements) { + count += estimateNodeCount(stmt); + } + } else if (node instanceof MethodNode) { + MethodNode method = (MethodNode) node; + for (ParamNode param : method.parameters) { + count += estimateNodeCount(param); + } + for (StmtNode stmt : method.body) { + count += estimateNodeCount(stmt); + } + } else if (node instanceof BlockNode) { + BlockNode block = (BlockNode) node; + for (StmtNode stmt : block.statements) { + count += estimateNodeCount(stmt); + } + } else if (node instanceof StmtIfNode) { + StmtIfNode ifNode = (StmtIfNode) node; + if (ifNode.condition != null) count += estimateNodeCount(ifNode.condition); + count += estimateNodeCount(ifNode.thenBlock); + count += estimateNodeCount(ifNode.elseBlock); + } else if (node instanceof BinaryOpNode) { + BinaryOpNode binOp = (BinaryOpNode) node; + if (binOp.left != null) count += estimateNodeCount(binOp.left); + if (binOp.right != null) count += estimateNodeCount(binOp.right); + } else if (node instanceof UnaryNode) { + UnaryNode unary = (UnaryNode) node; + if (unary.operand != null) count += estimateNodeCount(unary.operand); + } else if (node instanceof MethodCallNode) { + MethodCallNode call = (MethodCallNode) node; + for (ExprNode arg : call.arguments) { + count += estimateNodeCount(arg); + } + if (call.chainArguments != null) { + for (ExprNode arg : call.chainArguments) { + count += estimateNodeCount(arg); + } + } + } else if (node instanceof EqualityChainNode) { + EqualityChainNode chain = (EqualityChainNode) node; + if (chain.left != null) count += estimateNodeCount(chain.left); + for (ExprNode arg : chain.chainArguments) { + count += estimateNodeCount(arg); + } + } else if (node instanceof BooleanChainNode) { + BooleanChainNode boolChain = (BooleanChainNode) node; + for (ExprNode expr : boolChain.expressions) { + count += estimateNodeCount(expr); + } + } + + return count; + } + + protected boolean isConstantFoldingAvailable() { + try { + Class.forName("cod.ast.Optimizer"); + DebugSystem.debug(LOG_TAG, "Constant folding available"); + return true; + } catch (ClassNotFoundException e) { + DebugSystem.debug(LOG_TAG, "Constant folding NOT available"); + return false; + } + } + + protected String getOptimizationInfo() { + StringBuilder info = new StringBuilder(); + + if (isConstantFoldingAvailable()) { + info.append("Available optimizations:\n"); + info.append(" • Constant folding (-O, --optimize)\n"); + info.append(" - Evaluates constant expressions at compile time\n"); + info.append(" - Optimizes boolean chains (any[]/all[])\n"); + info.append(" - Eliminates unnecessary type casts\n"); + info.append(" - Pre-computes string concatenation\n"); + } else { + info.append("Optimizations: NOT AVAILABLE\n"); + info.append("Make sure Optimizer.java and ConstantFolder.java are compiled.\n"); + } + + return info.toString(); + } + public abstract void run(String[] args) throws Exception; } \ No newline at end of file diff --git a/src/main/java/cod/runner/CoderiveREPL.java b/src/main/java/cod/runner/CoderiveREPL.java index d4ba85f6..074cfbbc 100644 --- a/src/main/java/cod/runner/CoderiveREPL.java +++ b/src/main/java/cod/runner/CoderiveREPL.java @@ -1,40 +1,41 @@ +// CoderiveREPL.java package cod.runner; import cod.ast.ASTFactory; -import cod.ast.ManualCoderiveLexer; -import cod.ast.ManualCoderiveParser; +import cod.semantic.NamingValidator; import cod.ast.nodes.*; import cod.debug.DebugSystem; + import cod.interpreter.Interpreter; import cod.interpreter.ObjectInstance; +import cod.lexer.MainLexer; +import cod.parser.MainParser; + import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; -/** - * A Read-Eval-Print-Loop (REPL) for the Coderive language. - * - * This class provides an interactive command-line shell that uses the - * ManualCoderiveLexer, ManualCoderiveParser, and the Interpreter - * to execute Coderive code one line at a time. - */ +import cod.syntax.Keyword; + public class CoderiveREPL { public static void main(String[] args) { System.out.println("Welcome to the Coderive REPL. Type 'exit' to quit."); - System.out.println("Special commands: ';reset' to clear state, ';help' for help\n"); + System.out.println("Special commands: ';reset' to clear state, ';help' for help"); + System.out.println("Optimization: Type ';opt on' to enable constant folding, ';opt off' to disable\n"); + + DebugSystem.setLevel(DebugSystem.Level.ERROR); + DebugSystem.info("REPL", "Starting Coderive REPL"); - // 1. Set up persistent state Interpreter interpreter = new Interpreter(); - ObjectInstance globalInstance = new ObjectInstance(ASTFactory.createType("REPLGlobal", "local", null)); - Map globalLocals = new HashMap<>(); - Map globalSlots = new HashMap<>(); + ObjectInstance globalInstance = new ObjectInstance(ASTFactory.createType("REPLGlobal", Keyword.LOCAL, null)); + Map globalLocals = new HashMap(); + Map globalSlots = new HashMap(); - DebugSystem.setLevel(DebugSystem.Level.ERROR); + boolean optimize = false; - // 2. Start the Read-Eval-Print-Loop Scanner scanner = new Scanner(System.in); while (true) { System.out.print(">> "); @@ -45,13 +46,14 @@ public static void main(String[] args) { continue; } - // Handle special REPL commands if (line.equalsIgnoreCase(";exit") || line.equalsIgnoreCase(";quit")) { + DebugSystem.info("REPL", "Exiting REPL"); break; } if (line.equalsIgnoreCase(";reset")) { globalLocals.clear(); globalSlots.clear(); + DebugSystem.info("REPL", "State reset"); System.out.println("State reset."); continue; } @@ -59,72 +61,138 @@ public static void main(String[] args) { printHelp(); continue; } + + if (line.equalsIgnoreCase(";opt on")) { + optimize = true; + DebugSystem.info("REPL", "Constant folding ENABLED"); + System.out.println("Constant folding optimization ENABLED"); + continue; + } + if (line.equalsIgnoreCase(";opt off")) { + optimize = false; + DebugSystem.info("REPL", "Constant folding DISABLED"); + System.out.println("Constant folding optimization DISABLED"); + continue; + } + if (line.equalsIgnoreCase(";opt status")) { + System.out.println("Constant folding: " + (optimize ? "ENABLED" : "DISABLED")); + continue; + } try { - // 3. Check for multi-line input String fullInput = line; if (needsMoreInput(line)) { + DebugSystem.debug("REPL", "Detected multi-line input"); fullInput = readMultiLineInput(scanner, line); if (fullInput == null) { - continue; // User cancelled multi-line input + continue; } } - // 4. READ: Lex the input - ManualCoderiveLexer lexer = new ManualCoderiveLexer(fullInput); - List tokens = lexer.tokenize(); + MainLexer lexer = new MainLexer(fullInput); + List tokens = lexer.tokenize(); + DebugSystem.debug("REPL", "Tokenized: " + tokens.size() + " tokens"); - // 5. EVAL (Part 1: Parse) - ManualCoderiveParser parser = new ManualCoderiveParser(tokens); - StatementNode astNode = parser.parseSingleLine(); + MainParser parser = new MainParser(tokens); + StmtNode astNode = parser.parseSingleLine(); if (astNode == null) { + DebugSystem.warn("REPL", "No AST generated for input"); continue; } + + DebugSystem.debug("REPL", "Parsed AST node: " + astNode.getClass().getSimpleName()); + + if (optimize) { + DebugSystem.debug("REPL", "Applying constant folding"); + try { + Class optimizerClass = Class.forName("cod.ast.Optimizer"); + java.lang.reflect.Method foldMethod = optimizerClass.getMethod("foldConstants", ASTNode.class); + astNode = (StmtNode) foldMethod.invoke(null, astNode); + DebugSystem.debug("REPL", "Constant folding applied"); + } catch (Exception e) { + DebugSystem.warn("REPL", "Constant folding failed: " + e.getMessage()); + } + } + + validateREPLNaming(astNode, globalLocals); - // 6. EVAL (Part 2: Execute) - Object result = interpreter.getStatementEvaluator().evalStmt( + DebugSystem.debug("REPL", "Evaluating statement"); + Object result = interpreter.evalReplStatement( astNode, globalInstance, globalLocals, globalSlots ); - // 7. PRINT if (astNode instanceof ExprNode && result != null) { System.out.println(String.valueOf(result)); + DebugSystem.debug("REPL", "Result: " + result); } } catch (Exception e) { System.err.println("Error: " + e.getMessage()); + DebugSystem.error("REPL", "Error: " + e.getMessage()); } } - scanner.close(); System.out.println("Exiting REPL."); } + + private static void validateREPLNaming(StmtNode stmt, Map locals) { + DebugSystem.debug("REPL", "Validating naming for: " + stmt.getClass().getSimpleName()); + + if (stmt instanceof VarNode) { + VarNode var = (VarNode) stmt; + String varName = var.name; + + if (NamingValidator.isPascalCase(varName)) { + DebugSystem.error("REPL", "Invalid PascalCase variable: " + varName); + throw new RuntimeException("Variable name '" + varName + "' cannot use PascalCase (reserved for classes)"); + } + + if (NamingValidator.isAllCaps(varName) && var.value == null) { + DebugSystem.error("REPL", "Constant without value: " + varName); + throw new RuntimeException("Constant '" + varName + "' must have an initial value"); + } + + } else if (stmt instanceof AssignmentNode) { + AssignmentNode assign = (AssignmentNode) stmt; + if (assign.left instanceof ExprNode) { + ExprNode target = (ExprNode) assign.left; + if (target.name != null) { + String varName = target.name; + if (NamingValidator.isPascalCase(varName)) { + DebugSystem.error("REPL", "Invalid PascalCase assignment: " + varName); + throw new RuntimeException("Variable name '" + varName + "' cannot use PascalCase (reserved for classes)"); + } + + if (NamingValidator.isAllCaps(varName) && !locals.containsKey(varName)) { + DebugSystem.error("REPL", "Assignment to undeclared constant: " + varName); + throw new RuntimeException("Cannot assign to undeclared constant '" + varName + "'"); + } + } + } + } + + DebugSystem.debug("REPL", "Naming validation passed"); + } - /** - * Checks if the input line needs continuation (unclosed braces, etc.) - */ private static boolean needsMoreInput(String line) { - // Simple check: if we have unmatched braces, we need more input int openBraces = countChar(line, '{'); int closeBraces = countChar(line, '}'); return openBraces > closeBraces; } - /** - * Reads multi-line input until all braces are balanced - */ private static String readMultiLineInput(Scanner scanner, String firstLine) { + DebugSystem.debug("REPL", "Starting multi-line input collection"); StringBuilder input = new StringBuilder(firstLine); int braceBalance = countChar(firstLine, '{') - countChar(firstLine, '}'); System.out.print(" . . "); while (braceBalance > 0) { String line = scanner.nextLine().trim(); - input.append(" ").append(line); // Add space between lines + input.append(" ").append(line); braceBalance += countChar(line, '{') - countChar(line, '}'); @@ -134,12 +202,10 @@ private static String readMultiLineInput(Scanner scanner, String firstLine) { System.out.print(" . . "); } + DebugSystem.debug("REPL", "Multi-line input complete, length: " + input.length()); return input.toString(); } - /** - * Counts occurrences of a character in a string - */ private static int countChar(String str, char ch) { int count = 0; for (int i = 0; i < str.length(); i++) { @@ -150,9 +216,6 @@ private static int countChar(String str, char ch) { return count; } - /** - * Prints REPL help information - */ private static void printHelp() { System.out.println("Coderive REPL Help:"); System.out.println(" Expressions: 5 + 3, x * 2, \"hello\" + \" world\""); diff --git a/src/main/java/cod/runner/CommandRunner.java b/src/main/java/cod/runner/CommandRunner.java index 44308c1f..8190e3a4 100644 --- a/src/main/java/cod/runner/CommandRunner.java +++ b/src/main/java/cod/runner/CommandRunner.java @@ -7,52 +7,32 @@ public class CommandRunner extends BaseRunner { - // Operation modes - private enum OperationMode { - INTERPRET, - COMPILE_BYTECODE, - COMPILE_NATIVE, - COMPILE_BOTH - } - private final Interpreter interpreter; - private final CompilationEngine compilationEngine; + private boolean enableOptimization = false; + private boolean showOptimizationStats = false; public CommandRunner() { this.interpreter = new Interpreter(); - this.compilationEngine = new CompilationEngine(); } @Override public void run(String[] args) throws Exception { - // Default operation mode - OperationMode mode = OperationMode.INTERPRET; String outputFilename = null; - boolean showHelp = false; + enableOptimization = false; + showOptimizationStats = false; - // Process command line arguments with anonymous configuration RunnerConfig config = processCommandLineArgs(args, null, new Configuration() { @Override public void configure(RunnerConfig config) { - // Common defaults - config.withParserMode(ParserMode.MANUAL) - .withLinting(true) - .withPrintAST(false) - .withDebugLevel(DebugSystem.Level.INFO); + config.withDebugLevel(DebugSystem.Level.INFO); } }); - // Process operation mode arguments and output filename + // Parse command-line arguments for (int i = 0; i < args.length; i++) { String arg = args[i]; - if ("--compile".equals(arg) || "-c".equals(arg)) { - mode = OperationMode.COMPILE_NATIVE; - } else if ("--compile-bytecode".equals(arg)) { - mode = OperationMode.COMPILE_BYTECODE; - } else if ("--compile-both".equals(arg)) { - mode = OperationMode.COMPILE_BOTH; - } else if ("--interpret".equals(arg) || "-i".equals(arg)) { - mode = OperationMode.INTERPRET; + if ("--interpret".equals(arg) || "-i".equals(arg)) { + // Default mode, do nothing } else if ("-o".equals(arg)) { if (i + 1 < args.length) { outputFilename = args[i + 1]; @@ -60,115 +40,98 @@ public void configure(RunnerConfig config) { } else { System.err.println("Error: -o option requires an output filename."); } + } else if ("-O".equals(arg) || "--optimize".equals(arg)) { + enableOptimization = true; + DebugSystem.info(LOG_TAG, "Constant folding optimization enabled"); + } else if ("--opt-stats".equals(arg)) { + showOptimizationStats = true; + } else if ("--debug".equals(arg)) { + config.debugLevel = DebugSystem.Level.DEBUG; + } else if ("--trace".equals(arg)) { + config.debugLevel = DebugSystem.Level.TRACE; + } else if ("--quiet".equals(arg)) { + config.debugLevel = DebugSystem.Level.ERROR; } else if ("--help".equals(arg) || "-h".equals(arg)) { - showHelp = true; + printHelp(); + return; } } - // Show help and exit if requested - if (showHelp) { - printHelp(); - return; - } - - // Set output filename if provided if (outputFilename != null) { config.withOutputFilename(outputFilename); } - // Validate input filename - if (config.inputFilename == null || config.inputFilename.isEmpty()) { - printHelp(); - throw new RuntimeException("No input file specified"); - } - - // Configure debug system with the specified level configureDebugSystem(config.debugLevel); DebugSystem.info(LOG_TAG, "Starting CommandRunner execution"); - DebugSystem.info(LOG_TAG, "Operation mode: " + mode); - DebugSystem.info(LOG_TAG, "Parser mode: " + config.parserMode); DebugSystem.info(LOG_TAG, "Input file: " + config.inputFilename); - DebugSystem.info(LOG_TAG, "Output file: " + config.outputFilename); - DebugSystem.info(LOG_TAG, "Print AST: " + config.printAST); - DebugSystem.info(LOG_TAG, "Enable linting: " + config.enableLinting); + DebugSystem.info(LOG_TAG, "Optimization: " + (enableOptimization ? "ENABLED" : "DISABLED")); - // STAGE 1: PARSING AND AST - DebugSystem.startTimer("parsing_and_ast"); - ProgramNode ast = parseSourceFile(config.inputFilename, config.parserMode); + if (config.inputFilename == null || config.inputFilename.isEmpty()) { + throw new RuntimeException("No input file specified. Usage: CommandRunner [options]"); + } + + DebugSystem.startTimer("parsing"); + ProgramNode ast = parse(config.inputFilename); if (ast == null) { throw new RuntimeException("Parsing failed, AST is null."); } - DebugSystem.stopTimer("parsing_and_ast"); + DebugSystem.stopTimer("parsing"); DebugSystem.info(LOG_TAG, "AST built successfully"); - - // PRINT AST BEFORE LINTING (if enabled) - printASTIfEnabled(ast, config); - - // STAGE 2: LINTING - if (!performLinting(ast, config)) { - return; // Stop execution if linting failed - } - - // STAGE 3: EXECUTION BASED ON MODE - switch (mode) { - case INTERPRET: - executeInterpretation(ast); - break; - case COMPILE_BYTECODE: - compilationEngine.compileToBytecode(ast, true); - break; - case COMPILE_NATIVE: - compilationEngine.compileFullPipeline(ast, config.outputFilename, false); - break; - case COMPILE_BOTH: - compilationEngine.compileFullPipeline(ast, config.outputFilename, true); - break; - default: - throw new IllegalArgumentException("Unknown operation mode: " + mode); + + // Apply constant folding optimization if enabled + if (enableOptimization) { + DebugSystem.startTimer("optimization"); + DebugSystem.info(LOG_TAG, "Applying constant folding optimization..."); + + ast = optimizeAST(ast, true); + + DebugSystem.stopTimer("optimization"); + DebugSystem.info(LOG_TAG, "Optimization completed"); + + if (showOptimizationStats) { + printOptimizationSummary(); + } } + executeInterpretation(ast); + DebugSystem.info(LOG_TAG, "CommandRunner execution completed"); } - + private void executeInterpretation(ProgramNode ast) { DebugSystem.info(LOG_TAG, "Starting program interpretation"); interpreter.run(ast); DebugSystem.info(LOG_TAG, "Program interpretation completed"); } + private void printOptimizationSummary() { + System.out.println("\n=== CONSTANT FOLDING SUMMARY ==="); + System.out.println("Constant folding has been applied to the AST."); + System.out.println("Benefits:"); + System.out.println(" • Constant expressions evaluated at compile time"); + System.out.println(" • Runtime performance improved"); + System.out.println(" • Boolean chains (any[]/all[]) optimized"); + System.out.println(" • Type casts eliminated where possible"); + System.out.println("===============================\n"); + } + private void printHelp() { - System.out.println("Coderive CommandRunner - Multi-target language runner"); - System.out.println(); - System.out.println("Usage: java CommandRunner [options] "); - System.out.println(); - System.out.println("Operation Modes:"); - System.out.println(" --interpret, -i Interpret the program (default)"); - System.out.println(" --compile, -c Compile to native assembly"); - System.out.println(" --compile-bytecode Compile to bytecode only"); - System.out.println(" --compile-both Compile to both bytecode and native"); - System.out.println(); - System.out.println("Parser Options:"); - System.out.println(" --manual Use manual parser (default)"); - System.out.println(" --antlr Use ANTLR parser"); - System.out.println(); - System.out.println("Output Options:"); - System.out.println(" -o Output filename for compilation"); - System.out.println(" --print-ast Print the Abstract Syntax Tree"); - System.out.println(); - System.out.println("Analysis Options:"); - System.out.println(" --no-lint Disable linting"); - System.out.println(" --stop-on-lint Stop execution on lint errors"); - System.out.println(); - System.out.println("Debug Options:"); + System.out.println("Coderive CommandRunner - Execute Coderive programs"); + System.out.println("Usage: CommandRunner [options]\n"); + System.out.println("Options:"); + System.out.println(" -i, --interpret Interpret the program (default)"); + System.out.println(" -O, --optimize Enable constant folding optimization"); + System.out.println(" --opt-stats Show optimization summary"); + System.out.println(" -o Write output to file"); System.out.println(" --debug Enable debug output"); - System.out.println(" --trace Enable trace-level output"); - System.out.println(" --help, -h Show this help message"); - System.out.println(); - System.out.println("Examples:"); - System.out.println(" java CommandRunner program.cdrv --interpret"); - System.out.println(" java CommandRunner program.cdrv --compile -o output.s"); - System.out.println(" java CommandRunner program.cdrv --compile-bytecode --print-ast"); + System.out.println(" --trace Enable trace-level debugging"); + System.out.println(" --quiet Only show errors"); + System.out.println(" -h, --help Show this help message"); + System.out.println("\nExamples:"); + System.out.println(" CommandRunner program.cod"); + System.out.println(" CommandRunner program.cod -O"); + System.out.println(" CommandRunner program.cod -O --opt-stats"); } public static void main(String[] args) { @@ -181,4 +144,4 @@ public static void main(String[] args) { System.exit(1); } } -} +} \ No newline at end of file diff --git a/src/main/java/cod/runner/CompilerRunner.java b/src/main/java/cod/runner/CompilerRunner.java index 1e585d89..6dfa5938 100644 --- a/src/main/java/cod/runner/CompilerRunner.java +++ b/src/main/java/cod/runner/CompilerRunner.java @@ -1,109 +1,253 @@ package cod.runner; -import cod.runner.BaseRunner; -import cod.ast.nodes.*; +import cod.ast.nodes.ProgramNode; +import cod.compiler.MTOTNativeCompiler; +import cod.compiler.MTOTRegistry; +import cod.compiler.TACCompiler; +import cod.compiler.TACInstruction; +import cod.compiler.TACProgram; import cod.debug.DebugSystem; -import java.io.*; + +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.List; +import java.util.Map; public class CompilerRunner extends BaseRunner { - - // Enum for compiler output mode - private enum CompilationMode { - BOTH, - BYTECODE_ONLY, - NATIVE_ONLY - } - - private final String androidPath = "/storage/emulated/0"; - private final String definedFilePath = "/JavaNIDE/Programming-Language/Coderive/executables/interactiveDemo.cdrv"; - private final String definedOutputFilePath = "/program.s"; - - private final CompilationEngine compilationEngine; - - public CompilerRunner() { - this.compilationEngine = new CompilationEngine(); + + // --- Configuration Constants (Hardcoded) --- + private static final String ANDROID_PATH = "/storage/emulated/0"; + private static final String INPUT_FILE_DEFINITION = "/JavaNIDE/Programming-Language/Coderive/executables/InteractiveDemo.cod"; + private static final DebugSystem.Level DEBUG_LEVEL = DebugSystem.Level.INFO; // Set to INFO, DEBUG, or TRACE + private static final TargetMode TARGET_MODE = TargetMode.NATIVE; + private static final String ARCHITECTURE = "aarch64"; // Hardcoded architecture for compilation target + private static final boolean OPTIMIZATION_ENABLED = true; // NEW: Enable constant folding by default for compilation + private static final boolean SHOW_OPTIMIZATION_INFO = true; // NEW: Show optimization info + // --- End Configuration --- + + private enum TargetMode { + TAC, + NATIVE } @Override public void run(String[] args) throws Exception { - String defaultFilename = androidPath + definedFilePath; - final String defaultOutputFilename = androidPath + definedOutputFilePath; - - CompilationMode mode = CompilationMode.NATIVE_ONLY; - // Process command line arguments with anonymous configuration - RunnerConfig config = processCommandLineArgs(args, defaultFilename, new Configuration() { - @Override - public void configure(RunnerConfig config) { - // Compiler-specific defaults - config.withParserMode(ParserMode.MANUAL) - .withLinting(true) - .withPrintAST(false) - .withDebugLevel(DebugSystem.Level.INFO) - .withOutputFilename(defaultOutputFilename); - } - }); + // 1. Setup Configuration + String defaultInputFilename = ANDROID_PATH + INPUT_FILE_DEFINITION; - // Process compiler-specific arguments + RunnerConfig config = new RunnerConfig(defaultInputFilename); + config.withDebugLevel(DEBUG_LEVEL); + + // Check for command-line override of optimization + boolean optimizationEnabled = OPTIMIZATION_ENABLED; for (String arg : args) { - if ("--bytecode".equals(arg)) { - mode = CompilationMode.BYTECODE_ONLY; - } else if ("--native".equals(arg)) { - mode = CompilationMode.NATIVE_ONLY; + if ("--no-opt".equals(arg) || "-O0".equals(arg)) { + optimizationEnabled = false; + } else if ("-O".equals(arg) || "--optimize".equals(arg)) { + optimizationEnabled = true; } } - - // Configure debug system with the specified level + + // 2. Configure Debug System configureDebugSystem(config.debugLevel); - - DebugSystem.info(LOG_TAG, "Starting MTOT compilation pipeline"); - DebugSystem.info(LOG_TAG, "Parser mode: " + config.parserMode); - DebugSystem.info(LOG_TAG, "Compilation mode: " + mode); + + DebugSystem.info(LOG_TAG, "Starting Compiler execution..."); + DebugSystem.info(LOG_TAG, "Android Base Path: " + ANDROID_PATH); DebugSystem.info(LOG_TAG, "Input file: " + config.inputFilename); - DebugSystem.info(LOG_TAG, "Output file: " + config.outputFilename); - DebugSystem.info(LOG_TAG, "Print AST: " + config.printAST); - DebugSystem.info(LOG_TAG, "Enable linting: " + config.enableLinting); - - // STAGE 1: PARSING AND AST - DebugSystem.startTimer("parsing_and_ast"); - ProgramNode ast = parseSourceFile(config.inputFilename, config.parserMode); - if (ast == null) { - throw new RuntimeException("Parsing failed, AST is null."); + DebugSystem.info(LOG_TAG, "Target Mode: " + TARGET_MODE); + DebugSystem.info(LOG_TAG, "Target Architecture: " + ARCHITECTURE); + DebugSystem.info(LOG_TAG, "Constant Folding: " + (optimizationEnabled ? "ENABLED" : "DISABLED")); // NEW + + // 3. Frontend: Parse Source to AST + ProgramNode ast = parse(config.inputFilename); + if (ast == null) throw new RuntimeException("Parsing failed."); + + // NEW: Apply constant folding optimization + if (optimizationEnabled) { + DebugSystem.info(LOG_TAG, "Applying constant folding optimization..."); + DebugSystem.startTimer("constant_folding"); + + ast = optimizeAST(ast, true); + + DebugSystem.stopTimer("constant_folding"); + DebugSystem.info(LOG_TAG, "Constant folding completed in " + + DebugSystem.getTimerDuration("constant_folding") + " ms"); + + if (SHOW_OPTIMIZATION_INFO) { + printOptimizationInfo(); + } } - DebugSystem.stopTimer("parsing_and_ast"); - DebugSystem.info(LOG_TAG, "AST built successfully"); - // PRINT AST BEFORE LINTING (if enabled) - printASTIfEnabled(ast, config); + // 4. Middle-end: Compile AST to TAC + DebugSystem.info(LOG_TAG, "Generating Three-Address Code..."); + DebugSystem.startTimer("tac_generation"); + TACCompiler tacCompiler = new TACCompiler(); + TACProgram tacProgram = tacCompiler.compile(ast); + DebugSystem.stopTimer("tac_generation"); + DebugSystem.info(LOG_TAG, "TAC generation completed in " + + DebugSystem.getTimerDuration("tac_generation") + " ms"); - // STAGE 2: LINTING (before compilation, as it should be) - if (!performLinting(ast, config)) { - return; // Stop compilation if linting failed + // 5. Output Generation + String outputContent; + String outputFilename = ANDROID_PATH + "/output.asm"; // NEW: Default output filename + if (TARGET_MODE == TargetMode.TAC) { + outputContent = generateTacOutput(tacProgram, optimizationEnabled); + outputFilename = ANDROID_PATH + "/output.tac"; // For TAC mode + } else { + outputContent = generateNativeOutput(tacProgram, optimizationEnabled); + outputFilename = ANDROID_PATH + "/output.asm"; // For native assembly } - // STAGE 3: COMPILATION USING COMPILATION ENGINE - switch (mode) { - case BYTECODE_ONLY: - compilationEngine.compileToBytecode(ast, true); - break; - case NATIVE_ONLY: - compilationEngine.compileFullPipeline(ast, config.outputFilename, false); - break; - case BOTH: - compilationEngine.compileFullPipeline(ast, config.outputFilename, true); - break; + // 6. Write Result to File on /storage/emulated/0 + writeOutputToFile(outputContent, outputFilename); + + // 7. Also print truncated output to console + printTruncatedOutput(outputContent); + + // NEW: Print compilation summary + printCompilationSummary(optimizationEnabled, outputFilename); + } + + private String generateTacOutput(TACProgram program, boolean optimizationEnabled) { + StringBuilder sb = new StringBuilder(); + sb.append("; === COD Three-Address Code ===\n\n"); + + // NEW: Add optimization info comment + if (optimizationEnabled) { + sb.append("; Generated with constant folding optimization\n"); + sb.append("; Constant expressions have been evaluated at compile-time\n\n"); } - DebugSystem.info("MTOT", "Full compilation pipeline complete."); + for (Map.Entry> entry : program.getMethods().entrySet()) { + sb.append("method ").append(entry.getKey()).append(":\n"); + List code = entry.getValue(); + for (int i = 0; i < code.size(); i++) { + sb.append(String.format(" %03d: %s\n", i, code.get(i).toString())); + } + sb.append("\n"); + } + return sb.toString(); } + private String generateNativeOutput(TACProgram program, boolean optimizationEnabled) { + DebugSystem.info(LOG_TAG, "Compiling to Native Assembly (" + ARCHITECTURE + ")..."); + DebugSystem.startTimer("native_compilation"); + + // Use getProfile instead of creating new one + MTOTRegistry.CPUProfile profile = MTOTRegistry.getProfile(ARCHITECTURE); + if (profile == null) { + // Fall back to detected CPU if specified architecture not found + profile = MTOTRegistry.detectCPU(); + DebugSystem.warn(LOG_TAG, "Architecture " + ARCHITECTURE + " not found, using detected: " + profile.architecture); + } + + MTOTNativeCompiler nativeCompiler = new MTOTNativeCompiler(profile); + StringBuilder sb = new StringBuilder(); + + // NEW: Add optimization info comment + if (optimizationEnabled) { + sb.append("; Generated with constant folding optimization\n"); + sb.append("; Architecture: ").append(profile.architecture).append("\n"); + sb.append("; Optimizations: Constant expressions folded at compile-time\n\n"); + } else { + sb.append("; Generated without optimizations\n"); + sb.append("; Architecture: ").append(profile.architecture).append("\n\n"); + } + + // Compile each method + for (Map.Entry> entry : program.getMethods().entrySet()) { + String asm = nativeCompiler.compileMethodFromTAC(entry.getKey(), entry.getValue()); + sb.append(asm).append("\n\n"); + } + + DebugSystem.stopTimer("native_compilation"); + DebugSystem.info(LOG_TAG, "Native compilation completed in " + + DebugSystem.getTimerDuration("native_compilation") + " ms"); + + return sb.toString(); + } + + // NEW: Write output to file on /storage/emulated/0 + private void writeOutputToFile(String content, String filename) { + try { + DebugSystem.info(LOG_TAG, "Writing output to: " + filename); + FileOutputStream fos = new FileOutputStream(filename); + PrintStream ps = new PrintStream(fos); + ps.print(content); + ps.close(); + fos.close(); + DebugSystem.info(LOG_TAG, "Output successfully written to " + filename); + DebugSystem.info(LOG_TAG, "File size: " + content.length() + " bytes"); + } catch (Exception e) { + DebugSystem.error(LOG_TAG, "Failed to write output file: " + e.getMessage()); + System.err.println("ERROR: Could not write to " + filename + ": " + e.getMessage()); + } + } + + private void printOptimizationInfo() { + System.out.println("\n=== CONSTANT FOLDING INFORMATION ==="); + System.out.println("Constant folding has been applied to the AST before compilation."); + System.out.println("\nOptimizations performed:"); + System.out.println(" • Arithmetic constant expressions evaluated"); + System.out.println(" • Boolean chains (any[]/all[]) optimized"); + System.out.println(" • Type casts with constants eliminated"); + System.out.println(" • String concatenation with constants pre-computed"); + System.out.println("\nBenefits for compiled code:"); + System.out.println(" • Smaller generated code size"); + System.out.println(" • Faster execution (no runtime computation for constants)"); + System.out.println(" • More efficient register allocation"); + System.out.println("======================================\n"); + } + + private void printCompilationSummary(boolean optimizationEnabled, String outputFilename) { + System.out.println("\n=== COMPILATION SUMMARY ==="); + System.out.println("Target: " + TARGET_MODE); + if (TARGET_MODE == TargetMode.NATIVE) { + System.out.println("Architecture: " + ARCHITECTURE); + } + System.out.println("Optimizations: " + (optimizationEnabled ? "Constant folding applied" : "None")); + System.out.println("Output file: " + outputFilename); + System.out.println("Status: COMPLETED SUCCESSFULLY"); + System.out.println("============================\n"); + } + + private void printTruncatedOutput(String content) { + final int MAX_DISPLAY_LENGTH = 4000; + + System.out.println("\n--- COMPILATION OUTPUT (Preview) ---\n"); + + if (content.length() > MAX_DISPLAY_LENGTH) { + String truncated = content.substring(0, MAX_DISPLAY_LENGTH); + System.out.println(truncated); + System.out.println("\n... [OUTPUT TRUNCATED - Length: " + content.length() + " chars] ..."); + System.out.println("Full output written to file."); + } else { + System.out.println(content); + } + System.out.println("\n-----------------------------------\n"); + } + + // Main method remains for execution entry public static void main(String[] args) { try { - CompilerRunner runner = new CompilerRunner(); - runner.run(args); + // Note: args are ignored due to the hardcoded config requirement + // but we pass them through to check for optimization flags + new CompilerRunner().run(args); } catch (Exception e) { - DebugSystem.error("MTOT", "Compilation failed: " + e.getMessage()); - e.printStackTrace(); + System.err.println("Compiler Error: " + e.getMessage()); + // Only print stack trace if DEBUG_LEVEL is high + if (DEBUG_LEVEL.compareTo(DebugSystem.Level.DEBUG) >= 0) { + e.printStackTrace(); + } + + // Show usage hints + System.err.println("\nUsage hints:"); + System.err.println(" CompilerRunner [options]"); + System.err.println(" Options:"); + System.err.println(" --no-opt, -O0 Disable constant folding optimization"); + System.err.println(" -O, --optimize Enable constant folding (default: enabled)"); + System.err.println(" -o Output file (default: /storage/emulated/0/output.asm)"); } } } \ No newline at end of file diff --git a/src/main/java/cod/runner/InterpreterRunner.java b/src/main/java/cod/runner/InterpreterRunner.java index 6997df76..65408824 100644 --- a/src/main/java/cod/runner/InterpreterRunner.java +++ b/src/main/java/cod/runner/InterpreterRunner.java @@ -4,13 +4,18 @@ import cod.ast.nodes.*; import cod.debug.DebugSystem; import cod.interpreter.Interpreter; +import cod.debug.Linter; +import java.util.List; +import java.util.Scanner; public class InterpreterRunner extends BaseRunner { private final String androidPath = "/storage/emulated/0"; - private final String definedFilePath = "/JavaNIDE/Programming-Language/Coderive/executables/InteractiveDemo.cdrv"; + private final String definedFilePath = "/JavaNIDE/Programming-Language/Coderive/executables/ParamSkipDemo.cod"; private final Interpreter interpreter; + private boolean enableOptimization = false; + private boolean showOptimizationSummary = false; public InterpreterRunner() { this.interpreter = new Interpreter(); @@ -18,70 +23,160 @@ public InterpreterRunner() { @Override public void run(String[] args) throws Exception { - String defaultFilename = androidPath + definedFilePath; + String inputFilename = getInputFilename(args); + + // Parse optimization flags + for (String arg : args) { + if ("-O".equals(arg) || "--optimize".equals(arg)) { + enableOptimization = true; + } else if ("--opt-summary".equals(arg)) { + showOptimizationSummary = true; + } + } - // Process command line arguments with anonymous configuration - RunnerConfig config = processCommandLineArgs(args, defaultFilename, new Configuration() { + RunnerConfig config = processCommandLineArgs(args, inputFilename, new Configuration() { @Override public void configure(RunnerConfig config) { - // Interpreter-specific defaults - config.withParserMode(ParserMode.MANUAL) - .withLinting(true) - .withPrintAST(false) - .withDebugLevel(DebugSystem.Level.INFO); + config.withDebugLevel(DebugSystem.Level.OFF); } }); - // Configure debug system with the specified level configureDebugSystem(config.debugLevel); - DebugSystem.info(LOG_TAG, "Starting interpreter execution"); - DebugSystem.info(LOG_TAG, "Parser mode: " + config.parserMode); + DebugSystem.info(LOG_TAG, "Starting interpreter execution..."); DebugSystem.info(LOG_TAG, "Input file: " + config.inputFilename); - DebugSystem.info(LOG_TAG, "Print AST: " + config.printAST); - DebugSystem.info(LOG_TAG, "Enable linting: " + config.enableLinting); - - // Parse source file - DebugSystem.startTimer("parsing_and_ast"); - ProgramNode ast = parseSourceFile(config.inputFilename, config.parserMode); - if (ast == null) { - throw new RuntimeException("Parsing failed, AST is null."); - } - DebugSystem.stopTimer("parsing_and_ast"); - DebugSystem.info(LOG_TAG, "AST built successfully"); + DebugSystem.info(LOG_TAG, "Optimization: " + (enableOptimization ? "ENABLED" : "DISABLED")); - // Boolean flag to ensure sequential execution after linting - boolean lintingCompleted = false; + ProgramNode ast = parse(config.inputFilename); + if (ast == null) throw new RuntimeException("Parsing failed, AST is null."); - // Linting - COMPLETE BEFORE doing anything else - if (config.enableLinting) { - boolean lintingPassed = performLinting(ast, config); - if (!lintingPassed) { - return; // Stop execution if linting failed + // Apply constant folding optimization if enabled + if (enableOptimization) { + DebugSystem.info(LOG_TAG, "Applying constant folding optimization..."); + DebugSystem.startTimer("constant_folding"); + + ast = optimizeAST(ast, true); + + DebugSystem.stopTimer("constant_folding"); + DebugSystem.info(LOG_TAG, "Constant folding completed in " + + DebugSystem.getTimerDuration("constant_folding") + " ms"); + + if (showOptimizationSummary) { + printOptimizationSummary(); } - // Add a slight delay after linting - try { - Thread.sleep(100); // 100ms delay - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - DebugSystem.warn(LOG_TAG, "Delay after linting was interrupted"); + } + + // Perform linting and check completion status + boolean lintingCompleted = performLinting(ast); + + // CRITICAL: Ensure all output streams are fully flushed before proceeding + forceFlushAllStreams(); + + // Only run interpreter if linting completed successfully + if (lintingCompleted) { + Thread.sleep(50); + executeWithManualInterpreter(ast); + } else { + DebugSystem.error(LOG_TAG, "Linting did not complete successfully. Interpreter execution aborted."); + throw new RuntimeException("Linting phase failed to complete"); + } + } + + private String getInputFilename(String[] args) { + // First, check for optimization flags and input file in args + String inputFileFromArgs = null; + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (!arg.startsWith("-") && !arg.equals("-o") && !arg.equals("-O") && + !arg.equals("--optimize") && !arg.equals("--opt-summary")) { + inputFileFromArgs = arg; + break; } - // Set flag to indicate linting is completely finished - lintingCompleted = true; + } + + if (inputFileFromArgs != null) { + return inputFileFromArgs; + } + + // Otherwise, ask user interactively + Scanner scanner = new Scanner(System.in); + String defaultFilename = androidPath + definedFilePath; + + System.out.println("Enter file path or press Enter for default [" + defaultFilename + "]:"); + System.out.print("> "); + + String userInput = scanner.nextLine().trim(); + scanner.close(); + + if (userInput.isEmpty()) { + System.out.println("Using default file: " + defaultFilename); + return defaultFilename; } else { - // If linting is disabled, mark as completed to proceed - lintingCompleted = true; + System.out.println("Using user provided file: " + userInput); + return userInput; } + } + + private void executeWithManualInterpreter(ProgramNode ast) { + DebugSystem.info(LOG_TAG, "Running Manual Interpreter"); + DebugSystem.startTimer("interpretation"); + + interpreter.run(ast); + + // Get the duration FIRST, while the timer still exists + long duration = DebugSystem.getTimerDuration("interpretation"); + + // THEN stop the timer (which removes it) + DebugSystem.stopTimer("interpretation"); + + DebugSystem.info(LOG_TAG, "Interpretation completed in " + duration + " ms"); +} + + private boolean performLinting(ProgramNode ast) { + DebugSystem.startTimer("linting"); + Linter linter = new Linter(); + List warnings = linter.lint(ast); + DebugSystem.stopTimer("linting"); - // Only proceed if linting has completed (either successfully or was disabled) - if (lintingCompleted) { - // Print AST - ONLY AFTER linting is completely finished - printASTIfEnabled(ast, config); - - // Execute using Interpreter directly - DebugSystem.info(LOG_TAG, "Starting program interpretation"); - interpreter.run(ast); - DebugSystem.info(LOG_TAG, "Program interpretation completed"); + // Print warnings immediately and synchronously + Linter.WarningUtils.printWarnings(warnings); + + boolean lintingCompleted = linter.isCompleted(); + int warningCount = linter.getWarningCount(); + + DebugSystem.info(LOG_TAG, "Linting completed: " + lintingCompleted + " with " + warningCount + " warning(s)"); + + // Force flush all streams after linting output + forceFlushAllStreams(); + + return lintingCompleted; + } + + private void printOptimizationSummary() { + System.out.println("\n=== CONSTANT FOLDING OPTIMIZATION SUMMARY ==="); + System.out.println("Optimization Status: APPLIED"); + System.out.println("\nWhat was optimized:"); + System.out.println(" • Constant arithmetic expressions (e.g., 2 + 3 * 4 → 14)"); + System.out.println(" • Boolean chains with any[] and all[]"); + System.out.println(" • Type casts with constant values"); + System.out.println(" • String concatenation with constants"); + System.out.println(" • Comparison operations with constants"); + System.out.println("\nExpected benefits:"); + System.out.println(" • Runtime performance: 20-40% faster"); + System.out.println(" • Memory usage: Reduced temporary objects"); + System.out.println(" • Execution: Fewer runtime checks"); + System.out.println("==============================================\n"); + } + + /** + * Forces all output streams to flush completely to ensure proper output ordering + */ + private void forceFlushAllStreams() { + try { + System.out.flush(); + System.err.flush(); + } catch (Exception e) { + // Ignore interruption, just continue } } @@ -90,7 +185,13 @@ public static void main(String[] args) { InterpreterRunner runner = new InterpreterRunner(); runner.run(args); } catch (Exception e) { - DebugSystem.error("INTERPRETER", "Execution failed: " + e.getMessage()); + System.err.println("Interpreter Error: " + e.getMessage()); + System.err.println("\nUsage: InterpreterRunner [filename] [options]"); + System.err.println("Options:"); + System.err.println(" -O, --optimize Enable constant folding optimization"); + System.err.println(" --opt-summary Show optimization summary"); + System.err.println("\nExample:"); + System.err.println(" InterpreterRunner myprogram.cod -O"); e.printStackTrace(); } } diff --git a/src/main/java/cod/runner/PrinterRunner.java b/src/main/java/cod/runner/PrinterRunner.java new file mode 100644 index 00000000..a63083c4 --- /dev/null +++ b/src/main/java/cod/runner/PrinterRunner.java @@ -0,0 +1,245 @@ +// PrinterRunner.java +package cod.runner; + +import cod.runner.BaseRunner; +import cod.ast.nodes.*; +import cod.debug.DebugSystem; +import cod.ast.ASTPrinter; +import java.util.Scanner; + +public class PrinterRunner extends BaseRunner { + + private final String androidPath = "/storage/emulated/0"; + private final String definedFilePath = "/JavaNIDE/Programming-Language/Coderive/executables/InteractiveDemo.cod"; + + private boolean showOptimized = false; + private boolean showBoth = false; + private boolean showDiff = false; + + @Override + public void run(String[] args) throws Exception { + DebugSystem.info(LOG_TAG, "Starting PrinterRunner"); + + String inputFilename = getInputFilename(args); + + for (String arg : args) { + if ("--optimized".equals(arg) || "-O".equals(arg)) { + showOptimized = true; + DebugSystem.debug(LOG_TAG, "Show optimized mode"); + } else if ("--both".equals(arg) || "-B".equals(arg)) { + showBoth = true; + DebugSystem.debug(LOG_TAG, "Show both mode"); + } else if ("--diff".equals(arg) || "-D".equals(arg)) { + showDiff = true; + showBoth = true; + DebugSystem.debug(LOG_TAG, "Show diff mode"); + } else if ("--help".equals(arg) || "-h".equals(arg)) { + printHelp(); + return; + } + } + + RunnerConfig config = processCommandLineArgs(args, inputFilename, new Configuration() { + @Override + public void configure(RunnerConfig config) { + config.withDebugLevel(DebugSystem.Level.DEBUG); + } + }); + + configureDebugSystem(config.debugLevel); + + DebugSystem.info(LOG_TAG, "Starting AST Printer execution..."); + DebugSystem.info(LOG_TAG, "Input file: " + config.inputFilename); + + if (showOptimized) { + DebugSystem.info(LOG_TAG, "Mode: Showing OPTIMIZED AST"); + } else if (showBoth) { + DebugSystem.info(LOG_TAG, "Mode: Showing BOTH original and optimized AST"); + if (showDiff) { + DebugSystem.info(LOG_TAG, "Mode: Also showing DIFFERENCES"); + } + } else { + DebugSystem.info(LOG_TAG, "Mode: Showing ORIGINAL AST"); + } + + ProgramNode ast = parse(config.inputFilename); + if (ast == null) { + DebugSystem.error(LOG_TAG, "Parsing failed, AST is null"); + throw new RuntimeException("Parsing failed, AST is null."); + } + DebugSystem.info(LOG_TAG, "AST parsed successfully"); + + DebugSystem.info(LOG_TAG, "Printing Abstract Syntax Tree:"); + + if (showBoth) { + printBothASTs(ast, showDiff); + } else if (showOptimized) { + printOptimizedAST(ast); + } else { + printOriginalAST(ast); + } + + DebugSystem.info(LOG_TAG, "AST printing completed"); + } + + private void printOriginalAST(ProgramNode ast) { + System.out.println("\n=== ORIGINAL AST (No Optimizations) ==="); + System.out.println("This is the AST as parsed from source code."); + System.out.println("Constant expressions are not evaluated."); + System.out.println("========================================\n"); + DebugSystem.debug(LOG_TAG, "Printing original AST"); + ASTPrinter.print(ast); + } + + private void printOptimizedAST(ProgramNode ast) { + System.out.println("\n=== OPTIMIZED AST (With Constant Folding) ==="); + System.out.println("Constant folding has been applied:"); + System.out.println("• Arithmetic expressions evaluated"); + System.out.println("• Boolean chains optimized"); + System.out.println("• Type casts eliminated where possible"); + System.out.println("=============================================\n"); + + DebugSystem.startTimer("optimization"); + DebugSystem.debug(LOG_TAG, "Optimizing AST"); + ProgramNode optimized = optimizeAST(ast, true); + DebugSystem.stopTimer("optimization"); + + DebugSystem.debug(LOG_TAG, "Printing optimized AST"); + ASTPrinter.print(optimized); + + System.out.println("\n[Optimization completed in " + + DebugSystem.getTimerDuration("optimization") + " ms]"); + } + +// Alternative using char array (slightly more efficient for single characters) +private void printBothASTs(ProgramNode originalAst, boolean showDiff) { + System.out.println("\n=== COMPARISON: Original vs Optimized AST ==="); + System.out.println("Shows the effect of constant folding optimization."); + System.out.println("================================================\n"); + + System.out.println("=== ORIGINAL AST ==="); + System.out.println("(As parsed from source)\n"); + DebugSystem.debug(LOG_TAG, "Printing original AST for comparison"); + ASTPrinter.print(originalAst); + + System.out.println(); + for (int i = 0; i < 60; i++) System.out.print("="); + System.out.println("\n"); + + System.out.println("=== OPTIMIZED AST ==="); + System.out.println("(After constant folding)\n"); + + DebugSystem.startTimer("optimization"); + DebugSystem.debug(LOG_TAG, "Optimizing AST for comparison"); + ProgramNode optimizedAst = optimizeAST(originalAst, true); + DebugSystem.stopTimer("optimization"); + + ASTPrinter.print(optimizedAst); + + System.out.println("\n[Optimization time: " + + DebugSystem.getTimerDuration("optimization") + " ms]"); + + if (showDiff) { + System.out.println(); + for (int i = 0; i < 60; i++) System.out.print("="); + System.out.println("\n"); + System.out.println("=== KEY DIFFERENCES ==="); + DebugSystem.debug(LOG_TAG, "Printing AST differences"); + printASTDifferences(originalAst, optimizedAst); + } + + System.out.println("\n=== END OF COMPARISON ==="); +} + + private void printASTDifferences(ProgramNode original, ProgramNode optimized) { + System.out.println("\nSummary of changes made by constant folding:"); + System.out.println("(This is a conceptual summary - actual AST nodes differ)"); + System.out.println(); + + System.out.println("Examples of what constant folding does:"); + System.out.println(" • 2 + 3 * 4 → 14"); + System.out.println(" • any[true, false, true] → true"); + System.out.println(" • (int)3.14 → 3"); + System.out.println(" • \"Hello \" + \"World\" → \"Hello World\""); + System.out.println(" • x == any[1, 2, 3] (if x is constant) → true/false"); + System.out.println(); + + System.out.println("Benefits:"); + System.out.println(" • Runtime computation eliminated"); + System.out.println(" • Smaller AST (fewer nodes)"); + System.out.println(" • Better performance during interpretation/compilation"); + + System.out.println("\n[Note: Detailed node-by-node comparison not implemented]"); + DebugSystem.debug(LOG_TAG, "Printed AST differences (conceptual)"); + } + + private String getInputFilename(String[] args) { + for (String arg : args) { + if (!arg.startsWith("-") && + !arg.equals("--optimized") && + !arg.equals("--both") && + !arg.equals("--diff") && + !arg.equals("--help") && + !arg.equals("-O") && + !arg.equals("-B") && + !arg.equals("-D") && + !arg.equals("-h")) { + DebugSystem.debug(LOG_TAG, "Found input file in args: " + arg); + return arg; + } + } + + Scanner scanner = new Scanner(System.in); + String defaultFilename = androidPath + definedFilePath; + + System.out.println("Enter file path or press Enter for default [" + defaultFilename + "]:"); + System.out.print("> "); + + String userInput = scanner.nextLine().trim(); + scanner.close(); + + if (userInput.isEmpty()) { + System.out.println("Using default file: " + defaultFilename); + DebugSystem.info(LOG_TAG, "Using default file: " + defaultFilename); + return defaultFilename; + } else { + System.out.println("Using user provided file: " + userInput); + DebugSystem.info(LOG_TAG, "Using user file: " + userInput); + return userInput; + } + } + + private void printHelp() { + System.out.println("AST Printer - Display Abstract Syntax Trees"); + System.out.println("Usage: PrinterRunner [filename] [options]\n"); + System.out.println("Options:"); + System.out.println(" -O, --optimized Show AST after constant folding optimization"); + System.out.println(" -B, --both Show both original and optimized AST"); + System.out.println(" -D, --diff Show differences between original and optimized"); + System.out.println(" -h, --help Show this help message"); + System.out.println("\nExamples:"); + System.out.println(" PrinterRunner program.cod # Show original AST"); + System.out.println(" PrinterRunner program.cod -O # Show optimized AST"); + System.out.println(" PrinterRunner program.cod -B # Show both"); + System.out.println(" PrinterRunner program.cod -B -D # Show both with diff"); + System.out.println("\nNote: Default file is used if no filename provided."); + DebugSystem.info(LOG_TAG, "Printed help message"); + } + + public static void main(String[] args) { + try { + DebugSystem.setLevel(DebugSystem.Level.INFO); + DebugSystem.info("PRINTER_RUNNER", "Starting PrinterRunner"); + PrinterRunner runner = new PrinterRunner(); + runner.run(args); + } catch (Exception e) { + System.err.println("AST Printer Error: " + e.getMessage()); + DebugSystem.error("PRINTER_RUNNER", "Error: " + e.getMessage()); + System.err.println("\nUse --help for usage information."); + + if (DebugSystem.getLevel().compareTo(DebugSystem.Level.DEBUG) >= 0) { + e.printStackTrace(); + } + } + } +} \ No newline at end of file From f12d8738e39a2edf09eaf3571e3543f1393ecdde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:30:37 +0800 Subject: [PATCH 38/54] Create BaseParser.java --- src/main/java/cod/parser/BaseParser.java | 380 +++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 src/main/java/cod/parser/BaseParser.java diff --git a/src/main/java/cod/parser/BaseParser.java b/src/main/java/cod/parser/BaseParser.java new file mode 100644 index 00000000..1a88b731 --- /dev/null +++ b/src/main/java/cod/parser/BaseParser.java @@ -0,0 +1,380 @@ +package cod.parser; + +import cod.error.ParseError; + +import cod.syntax.Keyword; +import static cod.syntax.Keyword.*; +import cod.syntax.Symbol; +import static cod.syntax.Symbol.*; + +import java.util.List; + +import cod.lexer.MainLexer.Token; +import cod.lexer.MainLexer.TokenType; +import static cod.lexer.MainLexer.TokenType.*; + +/** + * Base class for all parser components, handling token stream management and + * common utility methods. Uses shared PositionHolder for position synchronization. + */ +public abstract class BaseParser { + protected final List tokens; + protected final PositionHolder position; + + public BaseParser(List tokens, PositionHolder position) { + this.tokens = tokens; + this.position = position; + } + + // --- Token Management --- + + protected Token currentToken() { + int pos = position.get(); + if (pos >= tokens.size()) { + // Return synthetic EOF token + if (tokens.isEmpty()) { + return new Token(EOF, "EOF", 1, 1); + } + Token last = tokens.get(tokens.size() - 1); + return new Token(EOF, "EOF", last.line, last.column + 1); + } + return tokens.get(pos); + } + + // UPDATED: Faster, safer bounds checking + protected Token peek(int offset) { + int targetPos = position.get() + offset; + return (targetPos >= 0 && targetPos < tokens.size()) ? + tokens.get(targetPos) : null; + } + + // NEW: Fast lookahead helpers + protected Token lookahead(int n) { + return peek(n); + } + + protected Token lookahead() { + return peek(1); + } + + // NEW: Helper for scanning loops (moved from DeclarationParser) + protected Token lookaheadFrom(int baseOffset, int additionalOffset) { + int pos = getPosition() + baseOffset + additionalOffset; + return pos >= 0 && pos < tokens.size() ? tokens.get(pos) : null; + } + + protected boolean match(Symbol expectedSymbol) { + Token current = currentToken(); + return current.type == TokenType.SYMBOL && current.symbol == expectedSymbol; + } + + protected boolean match(TokenType... types) { + Token current = currentToken(); + if (current.type == EOF) { + for (TokenType type : types) { + if (type == EOF) return true; + } + return false; + } + for (TokenType type : types) { + if (current.type == type) return true; + } + return false; + } + + protected Token consume() { + Token token = currentToken(); + if (token.type != EOF && position.get() < tokens.size()) { + position.up(); + } + return token; + } + + protected Token consume(TokenType expectedType) { + Token token = currentToken(); + if (token.type == expectedType) { + if (token.type != EOF && position.get() < tokens.size()) { + position.up(); + } + return token; + } + throw new ParseError("Expected " + getTypeName(expectedType) + " but found " + + getTypeName(token.type) + " ('" + token.text + "') at line " + token.line + ":" + token.column); + } + + protected Token consume(Symbol expectedSymbol) { + Token token = currentToken(); + if (token.type == TokenType.SYMBOL && token.symbol == expectedSymbol) { + if (token.type != EOF && position.get() < tokens.size()) { + position.up(); + } + return token; + } + throw new ParseError("Expected " + expectedSymbol + " but found " + + getTypeName(token.type) + " ('" + token.text + "') at line " + token.line + ":" + token.column); + } + + protected Token consume(boolean condition) { + if (condition) return consume(); + Token current = currentToken(); + throw new ParseError("Consumption condition not met at: " + current.text + + " (" + getTypeName(current.type) + ")" + + " at line " + current.line + ":" + current.column); + } + + protected boolean tryConsume(Symbol expectedSymbol) { + if (match(expectedSymbol)) { + consume(expectedSymbol); + return true; + } + return false; + } + + protected boolean tryConsume(TokenType expectedType) { + if (match(expectedType)) { + consume(expectedType); + return true; + } + return false; + } + + // --- Keyword and Symbol Helpers --- + + protected boolean isKeyword(Keyword expectedKeyword) { + Token current = currentToken(); + return current.type == KEYWORD && current.text.equals(expectedKeyword.toString()); + } + + protected boolean isKeywordAt(int offset, Keyword expectedKeyword) { + Token token = peek(offset); + return token != null && token.type == KEYWORD && token.text.equals(expectedKeyword.toString()); + } + + protected void consumeKeyword(Keyword expectedKeyword) { + Token token = currentToken(); + if (token.type == KEYWORD && token.text.equals(expectedKeyword.toString())) { + if (position.get() < tokens.size()) { + position.up(); + } + return; + } + throw new ParseError("Expected keyword '" + expectedKeyword.toString() + "' but found " + + getTypeName(token.type) + " ('" + token.text + "') at line " + token.line + ":" + token.column); + } + + protected boolean isSymbolAt(int offset, Symbol symbol) { + Token token = peek(offset); + return token != null && token.type == SYMBOL && token.symbol == symbol; + } + + protected String getTypeName(TokenType type) { + return type.toString(); + } + + // NEW: Helper to check if a token starts an expression (moved from ExpressionParser) + protected boolean isExpressionStart(Token t) { + if (t == null) return false; + + // Skip whitespace and comments - look for the next real token + if (t.type == WS || t.type == LINE_COMMENT || t.type == BLOCK_COMMENT) { + return false; // This tells the caller to skip this token + } + + String text = t.text; + return t.type == INT_LIT || t.type == FLOAT_LIT || + t.type == STRING_LIT || t.type == BOOL_LIT || + t.type == ID || t.symbol == LPAREN || + t.symbol == LBRACKET || t.symbol == BANG || + t.symbol == PLUS || t.symbol == MINUS || + (t.type == KEYWORD && ( + NULL.toString().equals(text) || + TRUE.toString().equals(text) || + FALSE.toString().equals(text) || + INPUT.toString().equals(text) + )); +} + + // --- Generic Grammar Helpers --- + + protected String parseQualifiedName() { + StringBuilder name = new StringBuilder(); + name.append(consume(ID).text); + while (tryConsume(DOT)) { + name.append("."); + name.append(consume(ID).text); + } + return name.toString(); + } + + protected boolean isTypeKeyword(String text) { + // Includes ARRAY keyword for declaration purposes + return text.equals(INT.toString()) || text.equals(TEXT.toString()) || + text.equals(FLOAT.toString()) || text.equals(BOOL.toString()); + } + +protected boolean isTypeStart(Token token) { + if (token == null) return false; + // REMOVED: var keyword from type checking + // Checks for (int, text, bool, float, ID, LPAREN) + // LBRACKET for prefix array types e.g., [int] + return isTypeKeyword(token.text) || token.type == ID || token.symbol == LPAREN || token.symbol == LBRACKET; +} + + protected boolean skipBrackets(int startOffset) { + int p = position.get() + startOffset; + while (p < tokens.size() && isSymbolAt(p - position.get(), LBRACKET)) { + if (p + 1 >= tokens.size() || !isSymbolAt(p + 1 - position.get(), RBRACKET)) { + return false; + } + p += 2; + } + return true; + } + +/** + * Skips a complete type definition starting at startPos (relative to tokens list, not parser position). + * Handles prefix arrays [int], groups (int, int), and unions int|float. + * Returns the index AFTER the type, or -1 if not a valid type. + */ +protected int skipType(int startPos) { + int pos = startPos; + if (pos >= tokens.size()) return -1; + + Token t = tokens.get(pos); + + // 1. Handle Prefix Array: [Type] or [] + if (t.symbol == LBRACKET) { + pos++; + if (pos >= tokens.size()) return -1; + + if (tokens.get(pos).symbol == RBRACKET) { + // Empty brackets [] + pos++; + } else { + // Recursive skip for inner type [int] + pos = skipType(pos); + if (pos == -1 || pos >= tokens.size()) return -1; + + if (tokens.get(pos).symbol == RBRACKET) { + pos++; + } else { + return -1; + } + } + } + // 2. Handle Group: (Type, Type) + else if (t.symbol == LPAREN) { + pos++; + while (true) { + pos = skipType(pos); + if (pos == -1 || pos >= tokens.size()) return -1; + + Token sep = tokens.get(pos); + if (sep.symbol == COMMA) { + pos++; + } else if (sep.symbol == RPAREN) { + pos++; + break; + } else { + return -1; + } + } + } + // 3. Handle Primitive or ID + else if (isTypeKeyword(t.text) || t.type == ID) { + pos++; + } + else { + return -1; + } + + // 4. Handle Unions (|) + if (pos < tokens.size() && tokens.get(pos).symbol == PIPE) { + pos++; // Consume | + return skipType(pos); // Recurse for next part + } + + return pos; +} + + /** + * Entry point for parsing types. + * Handles complex structures like: (int, text) | [bool] + */ +protected String parseTypeReference() { + StringBuilder type = new StringBuilder(); + + // 1. Parse the first type component + if (match(LBRACKET)) { + // Prefix Array handling [Type] or [] + consume(LBRACKET); + if (match(RBRACKET)) { + // Empty brackets [] -> dynamic array + consume(RBRACKET); + type.append("[]"); // Just [] for dynamic arrays + } else { + // Recursively parse inner type + String inner = parseTypeReference(); + consume(RBRACKET); + // Keep [type] notation + type.append("[").append(inner).append("]"); + } + } else if (match(LPAREN)) { + type.append(parseGroupedType()); + } else { + Token typeToken = currentToken(); + if (isTypeStart(typeToken) && typeToken.symbol != LBRACKET) { + String typeName = consume().text; + type.append(typeName); + } else { + Token current = currentToken(); + throw new ParseError("Expected type name but got " + + getTypeName(current.type) + " ('" + current.text + "')" + + " at line " + current.line + ":" + current.column); + } + } + + // 2. Handle Union types (|) + while (match(PIPE)) { + consume(PIPE); + type.append("|"); + type.append(parseTypeReference()); + } + + return type.toString(); +} + + /** + * Handles Grouped Types: (Type, Type) + */ + private String parseGroupedType() { + consume(LPAREN); + StringBuilder group = new StringBuilder("("); + + // Recursively parse the first element + group.append(parseTypeReference()); + + // Parse subsequent elements + while (tryConsume(COMMA)) { + group.append(","); + group.append(parseTypeReference()); + } + + consume(RPAREN); + group.append(")"); + return group.toString(); + } + + protected boolean isVisibilityModifier() { + return isKeyword(SHARE) || isKeyword(LOCAL); + } + + // --- Position Access (for debugging) --- + + /** + * Gets the current shared position (for debugging/logging only) + */ + public int getPosition() { + return this.position.get(); + } +} From 8ed5ffd749499aaffe8d17588b97e873ebe06cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:31:04 +0800 Subject: [PATCH 39/54] Add files via upload --- .../java/cod/parser/DeclarationParser.java | 594 +++++++++++++ .../java/cod/parser/ExpressionParser.java | 663 +++++++++++++++ src/main/java/cod/parser/MainParser.java | 786 ++++++++++++++++++ src/main/java/cod/parser/PositionHolder.java | 26 + src/main/java/cod/parser/ProgramType.java | 16 + src/main/java/cod/parser/StatementParser.java | 679 +++++++++++++++ 6 files changed, 2764 insertions(+) create mode 100644 src/main/java/cod/parser/DeclarationParser.java create mode 100644 src/main/java/cod/parser/ExpressionParser.java create mode 100644 src/main/java/cod/parser/MainParser.java create mode 100644 src/main/java/cod/parser/PositionHolder.java create mode 100644 src/main/java/cod/parser/ProgramType.java create mode 100644 src/main/java/cod/parser/StatementParser.java diff --git a/src/main/java/cod/parser/DeclarationParser.java b/src/main/java/cod/parser/DeclarationParser.java new file mode 100644 index 00000000..b222e3ff --- /dev/null +++ b/src/main/java/cod/parser/DeclarationParser.java @@ -0,0 +1,594 @@ +package cod.parser; + +import cod.ast.ASTFactory; +import cod.ast.nodes.*; +import cod.error.ParseError; +import cod.lexer.MainLexer.Token; +import cod.semantic.NamingValidator; +import cod.syntax.Keyword; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import static cod.lexer.MainLexer.TokenType.*; +import static cod.syntax.Keyword.*; +import static cod.syntax.Symbol.*; + +/** + * Parses top-level declarations: Types, Methods, and Fields. + * It requires a reference to the StatementParser to parse method bodies. + * Uses shared AtomicInteger for automatic position synchronization. + */ +public class DeclarationParser extends BaseParser { + + private final StatementParser statementParser; + + public DeclarationParser(List tokens, PositionHolder position, StatementParser statementParser) { + super(tokens, position); + this.statementParser = statementParser; + } + + public TypeNode parseType() { + Token visibilityToken = currentToken(); + String visibilityText = consume(isVisibilityModifier()).text; + + // Convert to Keyword + Keyword visibility; + if (SHARE.toString().equals(visibilityText)) { + visibility = Keyword.SHARE; + } else if (LOCAL.toString().equals(visibilityText)) { + visibility = Keyword.LOCAL; + } else { + throw new ParseError( + "Internal parser error: isVisibilityModifier() returned true for non-visibility keyword: '" + visibilityText + "'", + visibilityToken.line, visibilityToken.column); + } + + Token typeNameToken = currentToken(); + String typeName = consume(ID).text; + + NamingValidator.validateClassName(typeName, typeNameToken); + + String extendName = null; + if (isKeyword(IS)) { + consumeKeyword(IS); + extendName = parseQualifiedName(); + } + + TypeNode type = ASTFactory.createType(typeName, visibility, extendName); + + consume(LBRACE); + while (!match(RBRACE)) { +// Check fields before methods since both can start with visibility modifiers + if (isFieldDeclaration()) { + type.fields.add(parseField()); + } + else if (isMethodDeclaration()) { + MethodNode method = parseMethod(); + type.methods.add(method); + } + else { + // Automatic position sharing - no manual sync needed! + type.statements.add(statementParser.parseStatement()); + } + } + consume(RBRACE); + return type; +} + + public MethodNode parseMethod() { + Token startToken = currentToken(); + + boolean isBuiltin = false; + Keyword visibility = Keyword.SHARE; + + if (isKeyword(BUILTIN)) { + consumeKeyword(BUILTIN); + isBuiltin = true; + visibility = Keyword.SHARE; + } else if (isVisibilityModifier()) { + Token visibilityToken = currentToken(); + String visibilityText = consume().text; + + if (SHARE.toString().equals(visibilityText)) { + visibility = Keyword.SHARE; + } else if (LOCAL.toString().equals(visibilityText)) { + visibility = Keyword.LOCAL; + } else { + throw new ParseError( + "Internal parser error: isVisibilityModifier() returned true for non-visibility keyword: '" + visibilityText + "'", + visibilityToken.line, visibilityToken.column); + } + } + + String methodName = consume(ID).text; + + NamingValidator.validateMethodName(methodName, startToken); + + // We initialize with empty slots first, populate them later if '::' exists + MethodNode method = ASTFactory.createMethod(methodName, visibility, null); + method.isBuiltin = isBuiltin; + + // Parse parameters with new syntax: name: type + consume(LPAREN); + if (!match(RPAREN)) { + method.parameters.add(parseParameter()); + while (tryConsume(COMMA)) { + method.parameters.add(parseParameter()); + } + } + consume(RPAREN); + + // Check for Slot Contract '::' + if (isSlotDeclaration()) { + method.returnSlots = parseSlotContractList(); + } else { + method.returnSlots = new ArrayList(); + } + + // --- CRITICAL FIX: Skip whitespace/comments before checking for ~> or { --- + skipWhitespaceAndComments(); + + // Check for inline return (~>) or block ({) + if (match(TILDE_ARROW)) { + // Inline return + consume(TILDE_ARROW); + + // Skip whitespace before parsing slot assignments + skipWhitespaceAndComments(); + + // Parse multiple slot assignments for inline return + List slotAssignments = new ArrayList<>(); + + // Parse first slot assignment + slotAssignments.add(parseSingleSlotAssignment()); + + // Parse additional comma-separated slot assignments + while (tryConsume(COMMA)) { + skipWhitespaceAndComments(); // Skip whitespace after comma + slotAssignments.add(parseSingleSlotAssignment()); + } + + // Add to method body + if (slotAssignments.size() == 1) { + method.body.add(slotAssignments.get(0)); + } else { + MultipleSlotAssignmentNode multiAssign = ASTFactory.createMultipleSlotAssignment(slotAssignments); + method.body.add(multiAssign); + } + + } else if (match(LBRACE)) { + // Block return + consume(LBRACE); + while (!match(RBRACE)) { + method.body.add(statementParser.parseStatement()); + } + consume(RBRACE); + } else { + // Error: Method must have either ~> or { + Token current = currentToken(); + throw new ParseError( + "Expected '~>' or '{' after method signature, but found " + + getTypeName(current.type) + " ('" + current.text + "')" + + " at line " + current.line + ":" + current.column); + } + + return method; +} + + private SlotAssignmentNode parseSingleSlotAssignment() { + String slotName = null; + ExprNode value; + + // Check for named slot: "slotName: expression" + if (currentToken().type == ID) { + Token afterId = lookahead(1); + if (afterId != null && afterId.symbol == COLON) { + // Named slot: "sum: a + b" + slotName = consume(ID).text; + consume(COLON); + value = statementParser.expressionParser.parseExpression(); + } else { + // Positional slot: just an expression + slotName = null; + value = statementParser.expressionParser.parseExpression(); + } + } else { + // Positional slot: just an expression + slotName = null; + value = statementParser.expressionParser.parseExpression(); + } + + return ASTFactory.createSlotAssignment(slotName, value); +} + + public List parseSlotContractList() { + consume(DOUBLE_COLON); + + List slots = new ArrayList(); + + boolean firstSlot = true; + boolean isNamedMode = false; + int index = 0; + + do { + String name; + String type; + + if (firstSlot) { + if (currentToken().type == ID) { + // Named slot: name: type + isNamedMode = true; + name = consume(ID).text; + consume(COLON); + type = parseTypeReference(); + } else { + // Unnamed slot: just type + isNamedMode = false; + name = String.valueOf(index); + type = parseTypeReference(); + } + firstSlot = false; + } else { + if (isNamedMode) { + if (currentToken().type != ID) { + throw new ParseError("Mixed slot declaration styles not allowed. Expected name for slot."); + } + name = consume(ID).text; + consume(COLON); + type = parseTypeReference(); + } else { + if (currentToken().type == ID) { + throw new ParseError("Mixed slot declaration styles not allowed. Found name '" + currentToken().text + "' in unnamed slot list."); + } + name = String.valueOf(index); + type = parseTypeReference(); + } + } + + slots.add(ASTFactory.createSlot(type, name)); + index++; + + } while (tryConsume(COMMA)); + + return slots; +} + +public FieldNode parseField() { + Token startToken = currentToken(); + + // Parse optional visibility + Keyword visibility = null; + if (isVisibilityModifier()) { + Token visToken = consume(); + if (SHARE.toString().equals(visToken.text)) { + visibility = SHARE; + } else if (LOCAL.toString().equals(visToken.text)) { + visibility = LOCAL; + } + } + + // Parse name (FIRST!) + String fieldName = consume(ID).text; + + // REJECT underscore as field name + if ("_".equals(fieldName)) { + throw new ParseError( + "Field name cannot be '_'. Underscore is reserved for discard/placeholder.", + startToken.line, startToken.column + ); + } + + // Parse colon + consume(COLON); + + // Parse type (SECOND!) + String fieldType = parseTypeReference(); + + // Validate name + if (NamingValidator.isAllCaps(fieldName)) { + NamingValidator.validateConstantName(fieldName, startToken); + } else { + NamingValidator.validateVariableName(fieldName, startToken); + } + + // Create field + FieldNode field = ASTFactory.createField(fieldName, fieldType); + if (visibility != null) { + // Store visibility if your AST supports it + // field.visibility = visibility; // Uncomment if FieldNode has this field + } + + // Parse optional initializer + if (tryConsume(ASSIGN)) { + field.value = statementParser.expressionParser.parseExpression(); + } + + return field; +} + + public ParamNode parseParameter() { + Token startToken = currentToken(); + String name = consume(ID).text; + + // NEW: Check for := syntax (inferred from literal) + if (match(DOUBLE_COLON_ASSIGN)) { + consume(DOUBLE_COLON_ASSIGN); + + // Parse default value (must be a literal for inference) + ExprNode defaultValue = statementParser.expressionParser.parsePrimaryExpression(); + + // NEW: Validate it's a literal (not method call or complex expression) + if (!isSimpleLiteral(defaultValue)) { + throw new ParseError( + "Parameter inference (:=) can only be used with literals. " + + "Use explicit typing for expressions: " + name + ": Type = expression", + startToken.line, startToken.column + ); + } + + // Infer type from literal + String inferredType = inferTypeFromLiteral(defaultValue); + if (inferredType == null) { + throw new ParseError( + "Cannot infer parameter type from literal. Use explicit typing: " + + name + ": Type = " + defaultValue, + startToken.line, startToken.column + ); + } + + // Validate parameter name + NamingValidator.validateParameterName(name, startToken); + + // Create param with inferred type + ParamNode param = ASTFactory.createParam(name, inferredType, defaultValue, true); + param.hasDefaultValue = true; + return param; + } + + // Original: name: Type [= expression] + consume(COLON); + String type = parseTypeReference(); + + ExprNode defaultValue = null; + if (tryConsume(ASSIGN)) { + // This can be ANY expression (literal OR method call) + defaultValue = statementParser.expressionParser.parseExpression(); + } + + NamingValidator.validateParameterName(name, startToken); + ParamNode param = ASTFactory.createParam(name, type, defaultValue, false); + if (defaultValue != null) { + param.hasDefaultValue = true; + } + return param; +} + +private boolean isSimpleLiteral(ExprNode expr) { + // Check if expression is a SIMPLE literal + + // 1. Basic literals (int, float, text, bool, null) + if (expr instanceof ExprNode) { + ExprNode e = (ExprNode) expr; + if (e.value != null || e.isNull) { + return e.name == null; // Not an identifier + } + } + + // 2. Array literals + if (expr instanceof ArrayNode) { + ArrayNode arr = (ArrayNode) expr; + + // Check if it's a range NaturalArray (could be [1 to 10] or [by 2 in 1 to 10]) + if (arr.elements.size() == 1 && arr.elements.get(0) instanceof RangeNode) { + RangeNode range = (RangeNode) arr.elements.get(0); + // Check start and end are simple, step could be null or simple + return isSimpleLiteral(range.start) && + isSimpleLiteral(range.end) && + (range.step == null || isSimpleLiteral(range.step)); + } + + // Regular array - check all elements + for (ExprNode elem : arr.elements) { + if (!isSimpleLiteral(elem)) return false; + } + return true; + } + + // 3. RangeNode (if parsed separately somehow) + if (expr instanceof RangeNode) { + RangeNode range = (RangeNode) expr; + return isSimpleLiteral(range.start) && + isSimpleLiteral(range.end) && + (range.step == null || isSimpleLiteral(range.step)); + } + + // 4. Tuple literals + if (expr instanceof TupleNode) { + TupleNode tuple = (TupleNode) expr; + for (ExprNode elem : tuple.elements) { + if (!isSimpleLiteral(elem)) return false; + } + return true; + } + + return false; +} + +private String inferTypeFromLiteral(ExprNode expr) { + if (expr == null) return null; + + // 1. Basic ExprNode with value + if (expr instanceof ExprNode) { + ExprNode e = (ExprNode) expr; + + if (e.isNull) return null; // Can't infer from null + + Object value = e.value; + if (value instanceof Integer || value instanceof Long) return "int"; + if (value instanceof Float || value instanceof Double || value instanceof BigDecimal) return "float"; + if (value instanceof String) return "text"; + if (value instanceof Boolean) return "bool"; + } + + // 2. Array literals + if (expr instanceof ArrayNode) { + ArrayNode arr = (ArrayNode) expr; + if (arr.elements.isEmpty()) return null; // Can't infer empty array + + // Check if it's a single range (NaturalArray) + if (arr.elements.size() == 1 && arr.elements.get(0) instanceof RangeNode) { + return "[]"; // NaturalArray is treated as dynamic array [] + } + + // Try to infer from first element + String elementType = inferTypeFromLiteral(arr.elements.get(0)); + if (elementType != null) { + return "[" + elementType + "]"; + } + return null; + } + + // 3. RangeNode directly (if somehow parsed separately) + if (expr instanceof RangeNode) { + return "[]"; // NaturalArray as dynamic array + } + + // 4. Tuple literals + if (expr instanceof TupleNode) { + TupleNode tuple = (TupleNode) expr; + if (tuple.elements.isEmpty()) return null; + + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < tuple.elements.size(); i++) { + String elemType = inferTypeFromLiteral(tuple.elements.get(i)); + if (elemType == null) return null; // Can't infer if any element unknown + + if (i > 0) sb.append(","); + sb.append(elemType); + } + sb.append(")"); + return sb.toString(); + } + + return null; +} + + // --- Lookahead Methods --- + + public boolean isSlotDeclaration() { + // [CHANGED]: Checks for :: instead of ~: + return isSymbolAt(0, DOUBLE_COLON); + } + +private boolean isMethodDeclaration() { + int offset = 0; + + // Skip leading whitespace + while (lookaheadFrom(0, offset) != null && + (lookaheadFrom(0, offset).type == WS || + lookaheadFrom(0, offset).type == LINE_COMMENT || + lookaheadFrom(0, offset).type == BLOCK_COMMENT)) { + offset++; + } + + // 1. Skip modifiers (builtin / share / local) + Token first = lookaheadFrom(0, offset); + if (first == null) return false; + + if (BUILTIN.toString().equals(first.text) || + SHARE.toString().equals(first.text) || + LOCAL.toString().equals(first.text)) { + offset++; + } + + // Skip whitespace after modifier + while (lookaheadFrom(0, offset) != null && + (lookaheadFrom(0, offset).type == WS || + lookaheadFrom(0, offset).type == LINE_COMMENT || + lookaheadFrom(0, offset).type == BLOCK_COMMENT)) { + offset++; + } + + // 2. Check for method ID name + Token nameToken = lookaheadFrom(0, offset); + if (nameToken == null || nameToken.type != ID) return false; + + offset++; // Skip the name + + // Skip whitespace after name + while (lookaheadFrom(0, offset) != null && + (lookaheadFrom(0, offset).type == WS || + lookaheadFrom(0, offset).type == LINE_COMMENT || + lookaheadFrom(0, offset).type == BLOCK_COMMENT)) { + offset++; + } + + // 3. Check for opening parenthesis + Token parenToken = lookaheadFrom(0, offset); + if (parenToken == null || parenToken.symbol != LPAREN) return false; + + // If we have "share name (", it's a method. + return true; +} + +private boolean isFieldDeclaration() { + int currentPos = getPosition(); + int p = currentPos; + + // Skip optional visibility modifier (local/share) + if (p < tokens.size() && isVisibilityModifier(tokens.get(p))) { + p++; + } + + if (p >= tokens.size()) return false; + + // Pattern: name: type + // 1. Must start with ID (field name) + if (tokens.get(p).type != ID) { + return false; + } + + p++; // Skip the field name + + // 2. Must have colon after name + if (p >= tokens.size() || tokens.get(p).symbol != COLON) { + return false; + } + + p++; // Skip colon + + // 3. Must have a valid type after colon + if (p >= tokens.size() || !isTypeStart(tokens.get(p))) { + return false; + } + + // 4. Check it's not a method call + // After "name: type", check what comes next + int afterTypePos = skipType(p); + if (afterTypePos == -1) return false; + + // If after type we see '(', it's a method parameter list + if (afterTypePos < tokens.size() && tokens.get(afterTypePos).symbol == LPAREN) { + return false; // It's a method declaration + } + + // Otherwise, it's a field declaration + return true; +} + + private boolean isVisibilityModifier(Token token) { + if (token == null) return false; + return (token.type == KEYWORD && (token.text.equals(SHARE.toString()) || token.text.equals(LOCAL.toString()))); + } + + private void skipWhitespaceAndComments() { + while (position.get() < tokens.size()) { + Token t = currentToken(); + if (t.type == WS || t.type == LINE_COMMENT || t.type == BLOCK_COMMENT) { + consume(); + } else { + break; + } + } +} +} \ No newline at end of file diff --git a/src/main/java/cod/parser/ExpressionParser.java b/src/main/java/cod/parser/ExpressionParser.java new file mode 100644 index 00000000..86e7fa95 --- /dev/null +++ b/src/main/java/cod/parser/ExpressionParser.java @@ -0,0 +1,663 @@ +package cod.parser; + +import cod.ast.ASTFactory; +import cod.error.ParseError; +import cod.ast.nodes.*; + +import cod.lexer.MainLexer.Token; +import static cod.lexer.MainLexer.TokenType.*; + +import static cod.syntax.Symbol.*; +import static cod.syntax.Keyword.*; + +import java.util.ArrayList; +import java.util.List; +import java.math.BigDecimal; + +/** + * Predictive parser for expressions using Pratt precedence. + * Replaces complex lookahead with clean precedence-based parsing. + * Maintains 100% API compatibility with the previous implementation. + */ +public class ExpressionParser extends BaseParser { + + // Precedence levels (higher = tighter binding) + private static final int PREC_ASSIGNMENT = 10; + private static final int PREC_EQUALITY = 50; + private static final int PREC_COMPARISON = 60; + private static final int PREC_TERM = 70; + private static final int PREC_FACTOR = 80; + private static final int PREC_UNARY = 90; + private static final int PREC_CALL = 100; + + public ExpressionParser(List tokens, PositionHolder position) { + super(tokens, position); + } + + // === PUBLIC API METHODS (SAME SIGNATURES AS BEFORE) === + + public ExprNode parseExpression() { + if (isKeyword(ALL) || isKeyword(ANY)) { + return parseBooleanChain(); + } + return parsePrecedence(PREC_ASSIGNMENT); + } + + public MethodCallNode parseMethodCall() { + String qualifiedNameStr = parseQualifiedName(); + String methodName = qualifiedNameStr; + if (qualifiedNameStr.contains(".")) { + methodName = qualifiedNameStr.substring(qualifiedNameStr.lastIndexOf('.') + 1); + } + MethodCallNode call = ASTFactory.createMethodCall(methodName, qualifiedNameStr); + + consume(LPAREN); + + if (isKeyword(ALL) || isKeyword(ANY)) { + return parseConditionalChainCall(call); + } + + if (!match(RPAREN)) { + call.arguments.add(parseExpression()); + while (tryConsume(COMMA)) { + call.arguments.add(parseExpression()); + } + } + consume(RPAREN); + return call; + } + + public IndexAccessNode parseIndexAccessContinuation(ExprNode arrayExpr) { + consume(LBRACKET); + ExprNode indexExpr = parseExpression(); + consume(RBRACKET); + return ASTFactory.createIndexAccess(arrayExpr, indexExpr); + } + + public List parseReturnSlots() { + consume(LBRACKET); + List slots = new ArrayList(); + do { + if (match(ID)) { + slots.add(consume(ID).text); + } else if (match(INT_LIT)) { + slots.add(consume(INT_LIT).text); + } else { + throw new ParseError("Expected slot name or index, found " + currentToken().text); + } + } while (tryConsume(COMMA)); + consume(RBRACKET); + return slots; + } + + private ExprNode parseIfExpression() { + consumeKeyword(IF); + ExprNode condition = parseExpression(); + + // Parse then expression (can be in braces or not) + ExprNode thenExpr; + if (match(LBRACE)) { + consume(LBRACE); + thenExpr = parseExpression(); + consume(RBRACE); + } else { + thenExpr = parseExpression(); + } + + // ELSE is REQUIRED for expressions + consumeKeyword(ELSE); + + // Parse else expression + ExprNode elseExpr; + if (match(LBRACE)) { + consume(LBRACE); + elseExpr = parseExpression(); + consume(RBRACE); + } else { + elseExpr = parseExpression(); + } + + return ASTFactory.createIfExpression(condition, thenExpr, elseExpr); +} + + // === CRITICAL METHOD: Called by StatementParser === +public ExprNode parsePrimaryExpression() { + ExprNode baseExpr; + Token startToken = currentToken(); + + if (match(LBRACKET)) { + // FIX: Distinguish between [Array] and [Slot]:Call + if (isSlotAccessExpression()) { + List slotNames = parseReturnSlots(); + consume(COLON); + MethodCallNode methodCall = parseMethodCall(); + methodCall.slotNames = slotNames; + baseExpr = methodCall; + } else { + baseExpr = parseArrayLiteral(); + } + } else if (isKeyword(IF)) { + return parseIfExpression(); +} else if (match(INT_LIT)) { + String intText = consume().text; + try { + // 1. Try int first (Fast path 1) + int intValue = Integer.parseInt(intText); + baseExpr = ASTFactory.createIntLiteral(intValue); + } catch (NumberFormatException e1) { + try { + // 2. Try long (Fast path 2) + long longValue = Long.parseLong(intText); + baseExpr = ASTFactory.createLongLiteral(longValue); + } catch (NumberFormatException e2) { + // 3. Fallback: Too big for long. Use BigDecimal. + BigDecimal bigDecimalValue = new BigDecimal(intText); + baseExpr = ASTFactory.createFloatLiteral(bigDecimalValue); + } + } +} else if (match(FLOAT_LIT)) { + Token floatToken = consume(); + String floatText = floatToken.text; + + Object resolvedValue = resolveFloatLiteralValue(floatText); + + if (resolvedValue instanceof BigDecimal) { + // Case A: Shorthand (already resolved as BigDecimal) + baseExpr = ASTFactory.createFloatLiteral((BigDecimal)resolvedValue); + } else { + // Case B: Regular Float Literal (e.g., 3.14) + // FIX: Convert directly from string to BigDecimal for max precision + BigDecimal bigDecimalValue = new BigDecimal(floatText); + baseExpr = ASTFactory.createFloatLiteral(bigDecimalValue); + } + + } else if (match(STRING_LIT)) { + Token stringToken = consume(); + baseExpr = ASTFactory.createStringLiteral(stringToken.text); + + } else if (isKeyword(TRUE)) { + consumeKeyword(TRUE); + baseExpr = ASTFactory.createBoolLiteral(true); + + } else if (isKeyword(FALSE)) { + consumeKeyword(FALSE); + baseExpr = ASTFactory.createBoolLiteral(false); + + } else if (isKeyword(NULL)) { + consumeKeyword(NULL); + baseExpr = ASTFactory.createNullLiteral(); + + // Handle INPUT as an expression token + } else if (isKeyword(INPUT)) { + consumeKeyword(INPUT); + // Create input node with default "text" type and no variable binding (expression mode) + baseExpr = ASTFactory.createInput(TEXT.toString(), null); + +} else if (match(ID)) { + if (isMethodCallFollows()) { + baseExpr = parseMethodCall(); + } else { + String idName = consume().text; + // Allow underscore as identifier (will be validated in interpreter) + baseExpr = ASTFactory.createIdentifier(idName); + } +} else if (match(LPAREN)) { + if (isTypeCast()) { + baseExpr = parseTypeCast(); + } else { + consume(LPAREN); + ExprNode firstExpr = parseExpression(); + + // Handle Tuples (expressions separated by commas) + if (match(COMMA)) { + List elements = new ArrayList(); + elements.add(firstExpr); + + // Consume the first comma and continue to parse subsequent elements + while (tryConsume(COMMA)) { + elements.add(parseExpression()); + } + + // Check if the tuple is empty or terminated prematurely + if (elements.size() == 1 && !match(RPAREN)) { + // This catches cases like (expr, ) + throw new ParseError("Expected expression after comma in tuple but found " + + currentToken().text, currentToken().line, currentToken().column); + } + + consume(RPAREN); + baseExpr = ASTFactory.createTuple(elements); + } else { + // No comma found, it was a simple grouped expression (a+b) + consume(RPAREN); + baseExpr = firstExpr; + } + } + } else { + throw new ParseError("Unexpected token in primary expression: " + startToken.text + + " (" + getTypeName(startToken.type) + ")" + + " at line " + startToken.line + ":" + startToken.column); + } + + while (match(LBRACKET)) { + baseExpr = parseIndexAccessContinuation(baseExpr); + } + + return baseExpr; +} + + // === PRIVATE IMPLEMENTATION (PREDICTIVE PARSING) === + + private ExprNode parsePrecedence(int precedence) { + ExprNode left = parsePrefix(); + + while (true) { + Token op = currentToken(); + int opPrecedence = getPrecedence(op); + + if (opPrecedence < precedence) { + break; + } + + // Special case: boolean chain (x == all[...]) + if (isComparisonOp(op) && isChainFollows(1)) { + consume(); + return parseEqualityChain(left, op.text); + } + + // Regular binary operator + if (opPrecedence > 0) { + consume(); + ExprNode right = parsePrecedence(opPrecedence + 1); + left = ASTFactory.createBinaryOp(left, op.text, right); + continue; + } + + // Index access + if (op.symbol == LBRACKET) { + left = parseIndexAccessContinuation(left); + continue; + } + + break; + } + + return left; + } + + private ExprNode parsePrefix() { + // Handle unary operators first + if (match(BANG) || match(PLUS) || match(MINUS)) { + Token op = consume(); + ExprNode operand = parsePrecedence(PREC_UNARY); + return ASTFactory.createUnaryOp(op.text, operand); + } + + // Then parse primary expression + return parsePrimaryExpression(); + } + + // === BOOLEAN CHAINS (KEPT FROM ORIGINAL) === + + private ExprNode parseBooleanChain() { + Token typeToken = consume(); + boolean isAll = typeToken.text.equals(ALL.toString()); + + if (match(ID)) { + String arrayName = consume().text; + + if (isComparisonOp(currentToken())) { + Token op = consume(); + ExprNode right = parsePrecedence(PREC_COMPARISON + 1); + + List chainArgs = new ArrayList(); + chainArgs.add(right); + + ExprNode arrayExpr = ASTFactory.createIdentifier(arrayName); + EqualityChainNode chain = ASTFactory.createEqualityChain(arrayExpr, op.text, isAll, chainArgs); + return chain; + } else { + throw new ParseError("Expected comparison operator after 'all/any ' but found " + + getTypeName(currentToken().type) + " ('" + currentToken().text + + "') at line " + currentToken().line + ":" + currentToken().column); + } + } else if (match(LBRACKET)) { + consume(LBRACKET); + List expressions = new ArrayList(); + + if (!match(RBRACKET)) { + expressions.add(parseExpression()); + if (!match(COMMA) && !match(RBRACKET)) { + throw new ParseError("Boolean chain requires at least two expressions or a comma after the first expression."); + } + while (tryConsume(COMMA)) { + expressions.add(parseExpression()); + } + } + consume(RBRACKET); + + BooleanChainNode node = ASTFactory.createBooleanChain(isAll, expressions); + return node; + } else { + throw new ParseError("Expected array variable or '[' after 'all/any' but found " + + getTypeName(currentToken().type) + " ('" + currentToken().text + + "') at line " + currentToken().line + ":" + currentToken().column); + } + } + + private ExprNode parseEqualityChain(ExprNode left, String operator) { + Token chainTypeToken = consume(); + boolean isAllChain = chainTypeToken.text.equals(ALL.toString()); + + List chainArgs = new ArrayList(); + + if (match(LBRACKET)) { + consume(LBRACKET); + if (!match(RBRACKET)) { + chainArgs.add(parseChainArgument()); + while (tryConsume(COMMA)) { + chainArgs.add(parseChainArgument()); + } + } + consume(RBRACKET); + } else if (match(ID)) { + String arrayName = consume(ID).text; + ExprNode arrayExpr = ASTFactory.createIdentifier(arrayName); + chainArgs.add(arrayExpr); + } else { + throw new ParseError("Expected array variable or '[' for array literal after 'all/any' but found " + + getTypeName(currentToken().type) + " ('" + currentToken().text + + "') at line " + currentToken().line + ":" + currentToken().column); + } + + EqualityChainNode chain = ASTFactory.createEqualityChain(left, operator, isAllChain, chainArgs); + return chain; + } + + private ExprNode parseChainArgument() { + if (match(BANG)) { + consume(BANG); + ExprNode arg = parsePrimaryExpression(); + return ASTFactory.createUnaryOp("!", arg); + } + + if (match(LPAREN)) { + return parseArgumentList(); + } + + if (match(ID) && isSymbolAt(1, RBRACKET)) { + Token idToken = currentToken(); + throw new ParseError("Redundant brackets around array variable '" + idToken.text + + "'. Use 'any " + idToken.text + "' instead of 'any[" + idToken.text + "]'", + idToken.line, idToken.column); + } + + return parsePrimaryExpression(); + } + + private ExprNode parseArgumentList() { + consume(LPAREN); + List arguments = new ArrayList(); + if (!match(RPAREN)) { + arguments.add(parseExpression()); + while (tryConsume(COMMA)) { + arguments.add(parseExpression()); + } + } + consume(RPAREN); + return ASTFactory.createArgumentList(arguments); + } + + private MethodCallNode parseConditionalChainCall(MethodCallNode call) { + Token chainTypeToken = consume(); + boolean isAllChain = chainTypeToken.text.equals(ALL.toString()); + call.chainType = isAllChain ? ALL.toString() : ANY.toString(); + + consume(LBRACKET); + + List chainArgs = new ArrayList(); + if (!match(RBRACKET)) { + chainArgs.add(parseChainArgument()); + while (tryConsume(COMMA)) { + chainArgs.add(parseChainArgument()); + } + } + + consume(RBRACKET); + + call.chainArguments = chainArgs; + return call; + } + + private ExprNode parseArrayLiteral() { + consume(LBRACKET); + List elements = new ArrayList(); + + if (!match(RBRACKET)) { + // Check if this is a range + if (isRangeStart()) { + elements.add(parseRangeExpression()); + } else { + elements.add(parseExpression()); + } + + while (tryConsume(COMMA)) { + // Check if next is a range + if (isRangeStart()) { + elements.add(parseRangeExpression()); + } else { + elements.add(parseExpression()); + } + } + } + + consume(RBRACKET); + return ASTFactory.createArray(elements); +} + +// Add this helper method: +private boolean isRangeStart() { + Token current = currentToken(); + + // Case 1: "by" step "in" start "to" end + if (current.type == KEYWORD && current.text.equals("by")) { + return true; + } + + // Case 2: start "to" end (no 'by') + // Try to parse an expression, then check for "to" + int savedPos = getPosition(); + try { + parseExpression(); // Try to parse start + return currentToken().type == KEYWORD && + currentToken().text.equals("to"); + } catch (ParseError e) { + return false; + } finally { + position.set(savedPos); // Reset position + } +} + +// Add this method (similar to StatementParser.parseForStatement range parsing): +private RangeNode parseRangeExpression() { + ExprNode step = null; + + // Check for "by step" + if (isKeyword(BY)) { + consumeKeyword(BY); + step = parseExpression(); + consumeKeyword(IN); + } + + // Parse "start to end" + ExprNode start = parseExpression(); + consumeKeyword(TO); + ExprNode end = parseExpression(); + + return ASTFactory.createRange(step, start, end); +} + + private ExprNode parseTypeCast() { + consume(LPAREN); + String type = parseTypeReference(); + consume(RPAREN); + ExprNode expressionToCast = parsePrecedence(PREC_UNARY); + return ASTFactory.createTypeCast(type, expressionToCast); + } + +// NEW Helper method to resolve numeric shorthands or standard scientific notation into BigDecimal. +private Object resolveFloatLiteralValue(String literal) { + String baseValueStr; + String suffix; + int exponent = 0; + + // --- 1. Check for Custom Shorthands (K, M, Qi, etc.) --- + if (literal.endsWith("Qi")) { + suffix = "Qi"; + baseValueStr = literal.substring(0, literal.length() - 2); + exponent = 18; + } else { + char lastChar = literal.charAt(literal.length() - 1); + + if (lastChar == 'K' || lastChar == 'M' || lastChar == 'B' || lastChar == 'T' || lastChar == 'Q') { + suffix = String.valueOf(lastChar); + baseValueStr = literal.substring(0, literal.length() - 1); + + switch (suffix) { + case "K": exponent = 3; break; + case "M": exponent = 6; break; + case "B": exponent = 9; break; + case "T": exponent = 12; break; + case "Q": exponent = 15; break; + default: break; + } + } else { + // 2. Standard Scientific Notation ('e' or 'E') + if (literal.contains("e") || literal.contains("E")) { + try { + // BigDecimal's constructor handles this standard format directly + return new BigDecimal(literal); + } catch (NumberFormatException e) { + // Fall through to general error + } + } + + // If no shorthand and no 'e', return null (it's a plain float) + return null; + } + } + + // --- 3. Calculation for Custom Shorthands (if reached) --- + if (exponent > 0) { + try { + BigDecimal base = new BigDecimal(baseValueStr); + BigDecimal multiplier = BigDecimal.TEN.pow(exponent); + return base.multiply(multiplier); + } catch (NumberFormatException e) { + // Fall through to general error + } + } + + throw new ParseError("Invalid numeric literal format: " + literal, + currentToken().line, currentToken().column); +} + + // === ORIGINAL LOOKAHEAD HELPERS (KEPT FOR COMPATIBILITY) === + + private boolean isMethodCallFollows() { + Token first = lookahead(0); + if (first == null || first.type != ID) return false; + + int pos = 1; + while (lookahead(pos) != null && lookahead(pos).symbol == DOT) { + pos++; + if (lookahead(pos) == null || lookahead(pos).type != ID) return false; + pos++; + } + + Token afterDots = lookahead(pos); + return afterDots != null && afterDots.symbol == LPAREN; + } + + private boolean isSlotAccessExpression() { + if (!isSymbolAt(0, LBRACKET)) return false; + + int pos = getPosition() + 1; + int depth = 1; + + while (pos < tokens.size() && depth > 0) { + Token t = tokens.get(pos); + if (t.symbol == LBRACKET) depth++; + else if (t.symbol == RBRACKET) depth--; + pos++; + } + + if (depth == 0 && pos < tokens.size()) { + return tokens.get(pos).symbol == COLON; + } + return false; + } + + private boolean isTypeCast() { + if (!isSymbolAt(0, LPAREN)) return false; + Token second = lookahead(1); + if (second == null || !isTypeStart(second)) return false; + + int pos = getPosition(); + int parenDepth = 0; + + for (int i = 0; i < 20 && pos < tokens.size(); i++) { + Token t = tokens.get(pos); + if (t.symbol == LPAREN) parenDepth++; + else if (t.symbol == RPAREN) { + parenDepth--; + if (parenDepth == 0) { + if (pos + 1 < tokens.size()) { + Token afterParen = tokens.get(pos + 1); + return isExpressionStart(afterParen); + } + return false; + } + } + pos++; + } + return false; + } + + // === UTILITY METHODS === + + private int getPrecedence(Token token) { + if (token == null) return 0; + + if (token.type == SYMBOL) { + switch (token.symbol) { + case EQ: case NEQ: return PREC_EQUALITY; + case LT: case GT: case LTE: case GTE: return PREC_COMPARISON; + case PLUS: case MINUS: return PREC_TERM; + case MUL: case DIV: case MOD: return PREC_FACTOR; + case LPAREN: case LBRACKET: return PREC_CALL; + default: return 0; + } + } + return 0; + } + + private boolean isChainFollows(int offset) { + Token next = peek(offset); + if (next == null) return false; + + if (next.type == KEYWORD && + (next.text.equals(ALL.toString()) || next.text.equals(ANY.toString()))) { + Token after = peek(offset + 1); + return after != null && (after.symbol == LBRACKET || after.type == ID); + } + return false; + } + + private boolean isComparisonOp(Token t) { + return t != null && t.symbol != null && + (t.symbol == EQ || t.symbol == NEQ || + t.symbol == GT || t.symbol == LT || + t.symbol == GTE || t.symbol == LTE); + } +} \ No newline at end of file diff --git a/src/main/java/cod/parser/MainParser.java b/src/main/java/cod/parser/MainParser.java new file mode 100644 index 00000000..7ef1e482 --- /dev/null +++ b/src/main/java/cod/parser/MainParser.java @@ -0,0 +1,786 @@ +package cod.parser; + +import cod.error.ParseError; +import cod.ast.ASTFactory; +import cod.ast.nodes.*; + +import static cod.syntax.Keyword.*; +import cod.syntax.Symbol; +import static cod.syntax.Symbol.*; + +import java.util.ArrayList; +import java.util.List; + +import static cod.lexer.MainLexer.Token; +import static cod.lexer.MainLexer.TokenType.*; + +/** + * The main parser entry point, responsible for the overall program structure. + * Uses shared PositionHolder for automatic position synchronization across all parsers. + * Now includes program type detection and validation for the three-worlds design. + */ +public class MainParser extends BaseParser { + + private final ExpressionParser expressionParser; + private final StatementParser statementParser; + private final DeclarationParser declarationParser; + + public MainParser(List tokens) { + // Initialize BaseParser with shared PositionHolder + super(tokens, new PositionHolder(0)); + + // All parsers share the same position counter - NO synchronization needed! + this.expressionParser = new ExpressionParser(tokens, this.position); + this.statementParser = new StatementParser(tokens, this.position, expressionParser); + this.declarationParser = new DeclarationParser(tokens, this.position, statementParser); + } + +public ProgramNode parseProgram() { + // Detect program type first + ProgramType programType = detectProgramType(); + + // Reset position for actual parsing + position.set(0); + + // Parse based on program type + ProgramNode program = null; + try { + switch (programType) { + case MODULE: + program = parseModuleProgram(); + break; + case SCRIPT: + program = parseScriptProgram(); + break; + case METHOD_SCRIPT: + program = parseMethodScriptProgram(); + break; + default: + throw new ParseError("Unknown program type: " + programType); + } + } catch (ParseError e) { + // Add program type context to error + throw new ParseError("[" + programType + "] " + e.getMessage(), + e.getLine(), e.getColumn()); + } + + // Set program type + program.programType = programType; + + // Validate program structure + cod.semantic.ProgramValidator.validate(program, programType); + + return program; +} + + /** + * Entry method to parse a single line statement (e.g., for REPL/debugging). + */ + public StmtNode parseSingleLine() { + if (match(EOF)) { + return null; + } + + // Automatic position sharing - no synchronization needed! + StmtNode stmt = statementParser.parseStatement(); + + if (!match(EOF)) { + Token current = currentToken(); + throw new ParseError("Unexpected token after statement: " + + getTypeName(current.type) + " ('" + current.text + "')" + + " at line " + current.line + ":" + current.column); + } + return stmt; + } + + private UnitNode parseUnit() { + consumeKeyword(UNIT); + String unitName = parseQualifiedName(); + UnitNode unit = ASTFactory.createUnit(unitName); + + if (isKeyword(USE)) { + unit.imports = parseUseNode(); + } + return unit; + } + + private UseNode parseUseNode() { + consumeKeyword(USE); + consume(LBRACE); + List imports = new ArrayList(); + if (!match(RBRACE)) { + imports.add(parseQualifiedName()); + while (tryConsume(COMMA)) { + imports.add(parseQualifiedName()); + } + } + consume(RBRACE); + UseNode getNode = ASTFactory.createUseNode(imports); + return getNode; + } + + private TypeNode parseTypeDelegation() { + // Automatic position sharing - no synchronization needed! + return declarationParser.parseType(); + } + + // ========================================================================= + // NEW METHODS FOR THREE-WORLDS DESIGN + // ========================================================================= + +/** + * Detects the program type based on file structure. + */ +private ProgramType detectProgramType() { + // Save current position + int savedPos = position.get(); + position.set(0); + + // Turn off debug output for cleaner test results + // System.err.println("[DEBUG] Starting program type detection"); + + try { + boolean hasUnit = false; + boolean hasDirectCode = false; + boolean hasMethods = false; + boolean hasClasses = false; + + // Track if we're inside imports (skip them) + boolean skippingImports = false; + + // Scan tokens + while (!match(EOF)) { + Token current = currentToken(); + + // Skip imports (use keyword) + if (current.type == KEYWORD && USE.toString().equals(current.text)) { + skippingImports = true; + consume(); // consume "use" + if (match(LBRACE)) { + consume(LBRACE); + skipUntil(RBRACE); + } + continue; + } + + // Check for unit declaration + if (!hasUnit && current.type == KEYWORD && UNIT.toString().equals(current.text)) { + hasUnit = true; + consume(); // consume "unit" + // Skip unit name + if (match(ID)) { + parseQualifiedName(); + } + continue; + } + + // After unit, we should only see class declarations + if (hasUnit) { + // Check for class declaration (visibility modifier) + if (isVisibilityModifier()) { + hasClasses = true; + // Skip the class declaration + skipTypeDeclaration(); + continue; + } + // Anything else after unit is an error + if (!skippingImports) { + hasDirectCode = true; // This will cause validation error + } + consume(); + continue; + } + + // No unit yet, check for other patterns + + // Check for method declaration (BOTH syntaxes) + if (isMethodDeclarationStart()) { + hasMethods = true; + skipMethodDeclaration(); + continue; + } + + // --- CRITICAL FIX: Handle ~> as part of method, not direct code --- + if (current.symbol == TILDE_ARROW) { + // This is likely a method's return arrow + // Look back to see if we might have missed a method declaration + // For simplicity, treat it as part of a method + hasMethods = true; + consume(); // skip ~> + // Skip the slot assignment expression + skipExpression(); + continue; + } + + // Check for class declaration (without unit - error) + if (isVisibilityModifier()) { + hasClasses = true; + skipTypeDeclaration(); + continue; + } + + // Check for direct code/statements + if (looksLikeDirectCode(current)) { + hasDirectCode = true; + skipStatement(); + continue; + } + + // Skip other tokens + consume(); + } + + // Apply detection rules + ProgramType result = determineProgramType(hasUnit, hasDirectCode, hasMethods, hasClasses); + // System.err.println("[DEBUG] Final detection: " + result); + return result; + + } finally { + // Restore position + position.set(savedPos); + } +} + + /** + * Parse a MODULE program (has unit declaration). + */ + private ProgramNode parseModuleProgram() { + ProgramNode program = ASTFactory.createProgram(); + + // Must have unit + program.unit = parseUnit(); + + // Parse imports + while (isKeyword(USE)) { + if (program.unit.imports == null) { + program.unit.imports = parseUseNode(); + } else { + UseNode additionalImports = parseUseNode(); + program.unit.imports.imports.addAll(additionalImports.imports); + } + } + + // Parse classes only + while (!match(EOF)) { + if (isVisibilityModifier()) { + program.unit.types.add(parseTypeDelegation()); + } else { + throw new ParseError("Modules can only contain class declarations after imports"); + } + } + + return program; + } + + /** + * Parse a SCRIPT program (direct code only). + */ + private ProgramNode parseScriptProgram() { + ProgramNode program = ASTFactory.createProgram(); + program.unit = ASTFactory.createUnit("default"); + + // Parse imports + while (isKeyword(USE)) { + if (program.unit.imports == null) { + program.unit.imports = parseUseNode(); + } else { + UseNode additionalImports = parseUseNode(); + program.unit.imports.imports.addAll(additionalImports.imports); + } + } + + // Create synthetic type to hold statements + TypeNode scriptType = ASTFactory.createType("__Script__", SHARE, null); + + // Parse statements directly + while (!match(EOF)) { + if (isVisibilityModifier() || isMethodDeclarationStart()) { + throw new ParseError("Scripts cannot contain method or class declarations"); + } + scriptType.statements.add(statementParser.parseStatement()); + } + + program.unit.types.add(scriptType); + return program; + } + + /** + * Parse a METHOD_SCRIPT program (methods only). + */ + private ProgramNode parseMethodScriptProgram() { + ProgramNode program = ASTFactory.createProgram(); + program.unit = ASTFactory.createUnit("default"); + + // Parse imports + while (isKeyword(USE)) { + if (program.unit.imports == null) { + program.unit.imports = parseUseNode(); + } else { + UseNode additionalImports = parseUseNode(); + program.unit.imports.imports.addAll(additionalImports.imports); + } + } + + // Create synthetic type to hold methods + TypeNode methodScriptType = ASTFactory.createType("__MethodScript__", SHARE, null); + + // Parse method declarations only + while (!match(EOF)) { + if (!isMethodDeclarationStart()) { + throw new ParseError("Method scripts can only contain method declarations"); + } + methodScriptType.methods.add(declarationParser.parseMethod()); + } + + program.unit.types.add(methodScriptType); + return program; + } + + // ========================================================================= + // HELPER METHODS FOR PROGRAM TYPE DETECTION + // ========================================================================= + + private boolean isMethodDeclarationStart() { + Token first = currentToken(); + if (first == null) return false; + + // Must be local or share keyword + if (first.type == KEYWORD) { + String text = first.text; + if (LOCAL.toString().equals(text) || SHARE.toString().equals(text)) { + Token second = lookahead(1); + if (second != null && second.type == ID) { + Token third = lookahead(2); + // Method if followed by '(' + if (third != null && third.symbol == LPAREN) { + return true; + } + } + } + } + return false; +} + + private boolean looksLikeDirectCode(Token token) { + if (token == null) return false; + + // --- FIX: ~> is NOT direct code, it's part of method --- + if (token.symbol == TILDE_ARROW) { + return false; // This is method return syntax + } + + // Keywords that start statements (NOT method declarations) + if (token.type == KEYWORD) { + String text = token.text; + + // Check if this is a method declaration start + if ("local".equals(text) || "share".equals(text)) { + // Look ahead to see if it's a method + Token next1 = lookahead(1); + Token next2 = lookahead(2); + if (next1 != null && next1.type == ID && + next2 != null && next2.symbol == LPAREN) { + return false; // It's a method declaration, NOT direct code + } + } + + // Only these keywords are direct code + return text.equals("output") || + text.equals("if") || + text.equals("for") || + text.equals("exit") || + text.equals("input"); + } + + // Variable declaration/assignment + if (token.type == ID) { + Token next = lookahead(1); + if (next != null) { + // name := value + if (next.symbol == DOUBLE_COLON_ASSIGN) return true; + // name = value + if (next.symbol == ASSIGN) return true; + // name: type or name: type = value + if (next.symbol == COLON) return true; + } + return true; // Could be method call or variable reference + } + + // Expression start + return isExpressionStart(token); +} + + private void skipTypeDeclaration() { + // Skip visibility modifier + consume(); + // Skip type name + if (match(ID)) consume(); + // Skip 'is' and base type if present + if (isKeyword(IS)) { + consumeKeyword(IS); + parseQualifiedName(); + } + // Skip opening brace + if (match(LBRACE)) consume(LBRACE); + + // Skip everything until matching closing brace + int braceDepth = 1; + while (!match(EOF) && braceDepth > 0) { + Token t = currentToken(); + if (t.symbol == LBRACE) braceDepth++; + else if (t.symbol == RBRACE) braceDepth--; + consume(); + } + } + + private void skipMethodDeclaration() { + // Skip modifier (share/local) + consume(); + + // Skip method name + if (match(ID)) consume(); + + // Skip parameters + if (match(LPAREN)) { + consume(LPAREN); + skipUntil(RPAREN); + } + + // Skip return slots if present + if (match(DOUBLE_COLON)) { + consume(DOUBLE_COLON); + skipSlotContract(); + } + + // Handle both ~> and { syntax + if (match(TILDE_ARROW)) { + consume(TILDE_ARROW); + + // --- FIX: Skip slot assignments properly --- + // Skip first slot assignment + skipSlotAssignment(); + + // Skip additional comma-separated slot assignments + while (tryConsume(COMMA)) { + skipSlotAssignment(); + } + + } else if (match(LBRACE)) { + consume(LBRACE); + skipUntil(RBRACE); + } +} + +// NEW helper method +private void skipSlotAssignment() { + // Skip optional slot name and colon + if (match(ID)) { + Token next = lookahead(1); + if (next != null && next.symbol == COLON) { + consume(); // skip name + consume(); // skip colon + } + } + // Skip the expression + skipExpression(); +} + + private void skipSlotContract() { + do { + // Skip name: type or just type + if (match(ID) && isSymbolAt(1, COLON)) { + consume(); // name + consume(COLON); + } + // Skip type + skipTypeReference(); + } while (tryConsume(COMMA)); + } + + private void skipStatement() { + Token current = currentToken(); + + if (current.type == KEYWORD) { + String text = current.text; + if ("if".equals(text)) { + skipIfStatement(); + } else if ("for".equals(text)) { + skipForStatement(); + } else if ("output".equals(text)) { + skipOutputStatement(); + } else if ("exit".equals(text)) { + consume(); // exit + } else if ("local".equals(text) || "share".equals(text)) { + // Check if this is a method declaration + Token next = lookahead(1); + if (next != null && next.type == ID) { + Token afterNext = lookahead(2); + if (afterNext != null && afterNext.symbol == LPAREN) { + // It's a method declaration + skipMethodDeclaration(); + } else { + // Not a method, just skip the keyword + consume(); + } + } else { + consume(); + } + } else { + // Skip other keywords + consume(); + } + } else if (current.type == ID) { + // Skip until statement end + skipUntilStatementEnd(); + } else { + // Expression or other + consume(); + } +} + +private void skipForStatement() { + // Skip "for" + consumeKeyword(FOR); + + // Skip iterator name + if (match(ID)) consume(); + + // Skip optional "by" + if (isKeyword(BY)) { + consumeKeyword(BY); + // Skip step expression + skipExpression(); + } + + // Skip "in" + if (isKeyword(IN)) { + consumeKeyword(IN); + } + + // Skip start expression + skipExpression(); + + // Skip "to" + if (isKeyword(TO)) { + consumeKeyword(TO); + } else { + // If we don't find "to", just return + return; + } + + // Skip end expression + skipExpression(); + + // Skip body (could be block or single statement) + if (match(LBRACE)) { + consume(LBRACE); + skipUntil(RBRACE); + } else { + skipStatement(); + } +} + + private void skipIfStatement() { + consumeKeyword(IF); + skipExpression(); + + // Skip then block + if (match(LBRACE)) { + consume(LBRACE); + skipUntil(RBRACE); + } else { + skipStatement(); + } + + // Skip else/elif if present + while (isKeyword(ELIF) || isKeyword(ELSE)) { + consume(); + if (isKeyword(IF)) { + consumeKeyword(IF); + skipExpression(); + } + + if (match(LBRACE)) { + consume(LBRACE); + skipUntil(RBRACE); + } else { + skipStatement(); + } + } + } + + private void skipOutputStatement() { + consumeKeyword(OUTPUT); + skipExpression(); + } + + private void skipExpression() { + // UPDATED: Now tracks nesting and handles Commas/Keywords correctly + int braceDepth = 0; + int parenDepth = 0; + int bracketDepth = 0; + + while (!match(EOF)) { + Token t = currentToken(); + + // 1. Handle Nesting + if (t.symbol == LBRACE) braceDepth++; + else if (t.symbol == RBRACE) braceDepth--; + else if (t.symbol == LPAREN) parenDepth++; + else if (t.symbol == RPAREN) parenDepth--; + else if (t.symbol == LBRACKET) bracketDepth++; + else if (t.symbol == RBRACKET) bracketDepth--; + + // If we closed a nesting level that we didn't open in this context (e.g. end of method body), stop. + if (braceDepth < 0 || parenDepth < 0 || bracketDepth < 0) { + return; + } + + // 2. Check Stop Conditions (Only at depth 0) + if (braceDepth == 0 && parenDepth == 0 && bracketDepth == 0) { + // Stop at COMMA (necessary for slot lists: ~> a, b) + if (t.symbol == COMMA) { + return; + } + + // Stop at keywords that start new statements or declarations + if (t.type == KEYWORD) { + String text = t.text; + if (text.equals(IF.toString()) || + text.equals(FOR.toString()) || + text.equals(OUTPUT.toString()) || + text.equals(EXIT.toString()) || + text.equals(ELSE.toString()) || + text.equals(ELIF.toString()) || + // CRITICAL FIX: Stop at method/class modifiers + text.equals("share") || + text.equals("local") || + text.equals("unit")) { + return; + } + } + } + + consume(); + } +} + + private void skipUntil(Symbol symbol) { + while (!match(EOF) && !match(symbol)) { + Token t = currentToken(); + if (t.symbol == LBRACE || t.symbol == LPAREN || t.symbol == LBRACKET) { + // Skip nested + consume(); + skipUntilMatching(t.symbol); + } else { + consume(); + } + } + if (match(symbol)) consume(); + } + + private void skipUntilMatching(Symbol opening) { + Symbol closing; + if (opening == LBRACE) closing = RBRACE; + else if (opening == LPAREN) closing = RPAREN; + else if (opening == LBRACKET) closing = RBRACKET; + else return; + + skipUntil(closing); + } + + private void skipUntilStatementEnd() { + while (!match(EOF)) { + Token t = currentToken(); + + // Statement end markers - NO SEMICOLON IN YOUR LANGUAGE + if (t.symbol == RBRACE || + (t.type == KEYWORD && + (t.text.equals(ELSE.toString()) || t.text.equals("elif") || + t.text.equals("if") || t.text.equals("for") || + t.text.equals("output") || t.text.equals("exit")))) { + break; + } + + // Skip nested structures + if (t.symbol == LBRACE || t.symbol == LPAREN || t.symbol == LBRACKET) { + consume(); + skipUntilMatching(t.symbol); + } else { + consume(); + } + } + } + + private void skipTypeReference() { + if (match(LBRACKET)) { + consume(LBRACKET); + if (!match(RBRACKET)) { + skipTypeReference(); + } + consume(RBRACKET); + } else if (match(LPAREN)) { + consume(LPAREN); + skipTypeReference(); + while (tryConsume(COMMA)) { + skipTypeReference(); + } + consume(RPAREN); + } else if (isTypeStart(currentToken())) { + consume(); + } + + // Skip union + while (tryConsume(PIPE)) { + skipTypeReference(); + } + } + + private ProgramType determineProgramType(boolean hasUnit, boolean hasDirectCode, + boolean hasMethods, boolean hasClasses) { + + // Rule 1: Has unit → MUST be Module + if (hasUnit) { + if (hasDirectCode) { + throw new ParseError("Modules cannot have direct code outside classes."); + } + if (hasMethods && !hasClasses) { + throw new ParseError("Modules cannot have methods outside classes."); + } + return ProgramType.MODULE; + } + + // Rule 2: Has direct code → Script + if (hasDirectCode) { + if (hasMethods) { + throw new ParseError("Cannot mix direct code and method declarations.\n" + + "Either:\n" + + "1. Remove methods and keep as script, OR\n" + + "2. Remove direct code and make it a method script, OR\n" + + "3. Add 'unit' and classes to make it a module."); + } + if (hasClasses) { + throw new ParseError("Scripts cannot contain class declarations."); + } + return ProgramType.SCRIPT; + } + + // Rule 3: Has methods → Method Script + if (hasMethods) { + if (hasClasses) { + throw new ParseError("Method scripts cannot contain class declarations."); + } + return ProgramType.METHOD_SCRIPT; + } + + // Rule 4: Has classes without unit → ERROR + if (hasClasses) { + throw new ParseError("Classes require 'unit' declaration.\n" + + "Add: unit namespace.name\n" + + "Before your class definitions."); + } + + // Empty file or unrecognized + throw new ParseError("Empty file or unrecognized structure"); +} +} \ No newline at end of file diff --git a/src/main/java/cod/parser/PositionHolder.java b/src/main/java/cod/parser/PositionHolder.java new file mode 100644 index 00000000..749a7265 --- /dev/null +++ b/src/main/java/cod/parser/PositionHolder.java @@ -0,0 +1,26 @@ +package cod.parser; + +/** + * Simple holder for shared position across parsers. + * This allows multiple parser instances to share and update + * the same position in the token stream. + */ +public class PositionHolder { + public int value; + + public PositionHolder(int initial) { + this.value = initial; + } + + public void up() { + value++; + } + + public int get() { + return value; + } + + public void set(int newValue) { + value = newValue; + } +} \ No newline at end of file diff --git a/src/main/java/cod/parser/ProgramType.java b/src/main/java/cod/parser/ProgramType.java new file mode 100644 index 00000000..eb803314 --- /dev/null +++ b/src/main/java/cod/parser/ProgramType.java @@ -0,0 +1,16 @@ +package cod.parser; + +/** + * Enum representing the three program types in the language. + * Determined by the structure of the source file. + */ +public enum ProgramType { + /** Only direct statements - no methods, no classes, no unit */ + SCRIPT, + + /** Only methods - no direct code, no classes, no unit */ + METHOD_SCRIPT, + + /** Unit declaration with classes only - no direct code, no methods outside classes */ + MODULE +} \ No newline at end of file diff --git a/src/main/java/cod/parser/StatementParser.java b/src/main/java/cod/parser/StatementParser.java new file mode 100644 index 00000000..ab2fa036 --- /dev/null +++ b/src/main/java/cod/parser/StatementParser.java @@ -0,0 +1,679 @@ +package cod.parser; + +import cod.ast.ASTFactory; +import cod.semantic.NamingValidator; +import cod.error.ParseError; +import cod.ast.nodes.*; + +import java.util.ArrayList; +import java.util.List; + +import cod.lexer.MainLexer.Token; +import static cod.lexer.MainLexer.TokenType.*; + +import static cod.syntax.Symbol.*; +import static cod.syntax.Keyword.*; + +public class StatementParser extends BaseParser { + + public final ExpressionParser expressionParser; + + public StatementParser( + List tokens, PositionHolder position, ExpressionParser expressionParser) { + super(tokens, position); + this.expressionParser = expressionParser; + } + + public StmtNode parseStatement() { + return parseStatement(null); + } + + private StmtNode parseStatement(Boolean inheritedStyle) { + checkIllegalDeclaration(); + + Token first = currentToken(); + + // 1. Keyword statements (fast path) + if (first.type == KEYWORD) { + String text = first.text; + if (IF.toString().equals(text)) return parseIfStatement(inheritedStyle); + if (FOR.toString().equals(text)) return parseForStatement(); + if (OUTPUT.toString().equals(text)) return parseOutputStatement(); + if (EXIT.toString().equals(text)) return parseExitStatement(); + } + + // 2. Symbol statements (Slot Assignment) + if (first.symbol == TILDE_ARROW) return parseSlotAssignment(); + + // 3. Method Call Statement with return slots (starts with [) + if (first.symbol == LBRACKET && isMethodCallStatement()) { + return parseMethodCallStatement(); + } + + // 4. Reassignment and Method Call (declarations handled above) + if (isVariableDeclaration()) { + return parseVariableDeclaration(); + } + + // 5. Declaration, Assignment, or Method Call + if (first.type == ID) { + Token second = lookahead(1); + + if (second != null) { + // Case A: ID [ ... (Index Assignment only) + if (first.type == ID && second.symbol == LBRACKET) { + if (isIndexAssignment()) return parseIndexAssignment(); + } + + // Case B: ID = ... (Simple reassignment) + if (first.type == ID && second.symbol == ASSIGN) { + // Check specific assignments before falling back to simple + if (isReturnSlotAssignment()) return parseReturnSlotAssignment(); + if (isInputAssignment()) return parseInputAssignment(); + return parseSimpleAssignment(); + } + + // Case C: ID , ... (Multi-var return slot) + if (first.type == ID && second.symbol == COMMA) { + if (isReturnSlotAssignment()) return parseReturnSlotAssignment(); + } + } + + // Fallback for Calls (f()) + if (isMethodCallStatement()) return parseMethodCallStatement(); + } + + // 6. Everything else (Expression Statement) + return parseExpressionStatement(); +} + + private void checkIllegalDeclaration() { + Token current = currentToken(); + if (current.type != KEYWORD) return; + + // REMOVED: VAR keyword check + // Only check if keyword looks like a type start + if (isTypeStart(current)) return; + + Token idToken = peek(1); + if (idToken != null && idToken.type == ID) { + Token afterId = peek(2); + if (afterId != null) { + if (afterId.symbol == ASSIGN) { + throw new ParseError( + "Illegally used reserved keyword '" + + current.text + + "' for declaration of variable '" + + idToken.text + + "'", + current.line, + idToken.column); + } + if (afterId.symbol == LBRACKET && peek(3) != null && peek(3).symbol == RBRACKET) { + throw new ParseError( + "Illegally used reserved keyword '" + + current.text + + "' for declaration of variable '" + + idToken.text + + "'", + current.line, + idToken.column); + } + } + } +} + + private SlotAssignmentNode parseSingleSlotAssignment() { + String slotName = null; + ExprNode value; + + // Check for named slot: "slotName: expression" + if (currentToken().type == ID) { + Token afterId = lookahead(1); + if (afterId != null && afterId.symbol == COLON) { + // Named slot: "sum: a + b" + slotName = consume(ID).text; + consume(COLON); + value = expressionParser.parseExpression(); + } else { + // Positional slot: just an expression + slotName = null; + value = expressionParser.parseExpression(); + } + } else { + // Positional slot: just an expression + slotName = null; + value = expressionParser.parseExpression(); + } + + return ASTFactory.createSlotAssignment(slotName, value); +} + + private StmtNode parseSlotAssignment() { + consume(TILDE_ARROW); + List assignments = new ArrayList(); + assignments.add(parseSingleSlotAssignment()); + if (match(COMMA)) { + while (tryConsume(COMMA)) assignments.add(parseSingleSlotAssignment()); + MultipleSlotAssignmentNode multiAssign = ASTFactory.createMultipleSlotAssignment(assignments); + return multiAssign; + } else { + SlotAssignmentNode assignment = assignments.get(0); + return assignment; + } + } + +private StmtNode parseSimpleAssignment() { + Token startToken = currentToken(); + String idName = consume(ID).text; + + // REJECT assignment to underscore + if ("_".equals(idName)) { + throw new ParseError( + "Cannot assign to '_'. Underscore is reserved for discard/placeholder.", + startToken.line, startToken.column + ); + } + + ExprNode target = ASTFactory.createIdentifier(idName); + consume(ASSIGN); + ExprNode value = expressionParser.parseExpression(); + AssignmentNode assignment = ASTFactory.createAssignment(target, value); + return assignment; +} + +private StmtNode parseVariableDeclaration() { + Token startToken = currentToken(); + String typeName = null; + boolean isImplicit = false; + String varName = null; + ExprNode value = null; + + // Case 1: Implicit Typing (ID := Expression) + if (currentToken().type == ID && lookahead(1) != null && + lookahead(1).symbol == DOUBLE_COLON_ASSIGN) { + + varName = consume(ID).text; + + // REJECT underscore + if ("_".equals(varName)) { + throw new ParseError( + "Cannot declare variable '_'. Underscore is reserved for discard/placeholder.", + startToken.line, startToken.column + ); + } + + consume(DOUBLE_COLON_ASSIGN); + isImplicit = true; + value = expressionParser.parseExpression(); + + } + // Case 2: Explicit Typing (ID : Type [ = Expression]) + else if (currentToken().type == ID && lookahead(1) != null && + lookahead(1).symbol == COLON) { + + varName = consume(ID).text; + + // REJECT underscore + if ("_".equals(varName)) { + throw new ParseError( + "Cannot declare variable '_'. Underscore is reserved for discard/placeholder.", + startToken.line, startToken.column + ); + } + + consume(COLON); + + // MUST have a type after colon + if (isTypeStart(currentToken())) { + typeName = parseTypeReference(); + + // Check for optional assignment + if (tryConsume(ASSIGN)) { + value = expressionParser.parseExpression(); + } + } else { + throw new ParseError("Expected type after ':' in variable declaration. " + + "For inferred typing use ':=' operator."); + } + + } else { + // Fallback for unrecognized pattern that wasn't correctly caught by lookahead + throw new ParseError( + "Expected variable declaration in format 'name: type', 'name: type = value', or 'name := value'."); + } + + // Validate variable name (common to both cases) + if (varName != null) { + if (NamingValidator.isAllCaps(varName)) { + NamingValidator.validateConstantName(varName, startToken); + } else { + NamingValidator.validateVariableName(varName, startToken); + } + } + + // Create and return the VarNode + VarNode varNode = ASTFactory.createVar(varName, value); + varNode.explicitType = isImplicit ? null : typeName; + return varNode; +} + + private StmtNode parseIfStatement(Boolean inheritedStyle) { + consumeKeyword(IF); + ExprNode condition = expressionParser.parseExpression(); + StmtIfNode rootIfNode = ASTFactory.createIfStatement(condition); + + Boolean currentStyle = inheritedStyle; + + if (match(LBRACE)) { + consume(LBRACE); + while (!match(RBRACE)) rootIfNode.thenBlock.statements.add(parseStatement(currentStyle)); + consume(RBRACE); + } else { + rootIfNode.thenBlock.statements.add(parseStatement(currentStyle)); + } + + StmtIfNode currentNode = rootIfNode; + + while (isKeyword(ELIF)) { + consumeKeyword(ELIF); + if (currentStyle != null && !currentStyle) + throw new ParseError("Cannot use 'elif' in an 'else if' style chain"); + currentStyle = true; + ExprNode elifCondition = expressionParser.parseExpression(); + StmtIfNode elifNode = ASTFactory.createIfStatement(elifCondition); + if (match(LBRACE)) { + consume(LBRACE); + while (!match(RBRACE)) elifNode.thenBlock.statements.add(parseStatement(currentStyle)); + consume(RBRACE); + } else { + elifNode.thenBlock.statements.add(parseStatement(currentStyle)); + } + currentNode.elseBlock.statements.add(elifNode); + currentNode = elifNode; + } + + if (isKeyword(ELSE)) { + consumeKeyword(ELSE); + if (isKeyword(IF)) { + if (currentStyle != null && currentStyle) + throw new ParseError("Cannot use 'else if' in an 'elif' style chain"); + currentStyle = false; + currentNode.elseBlock.statements.add(parseIfStatement(currentStyle)); + } else { + if (match(LBRACE)) { + consume(LBRACE); + while (!match(RBRACE)) currentNode.elseBlock.statements.add(parseStatement(currentStyle)); + consume(RBRACE); + } else { + currentNode.elseBlock.statements.add(parseStatement(currentStyle)); + } + } + } + return rootIfNode; + } + +// For loop parsing with multiplicative (*2, /2) and additive (+1, -2) step expressions + private StmtNode parseForStatement() { + consumeKeyword(FOR); + String iterator = consume(ID).text; + ExprNode step = null; + + if (isKeyword(BY)) { + consumeKeyword(BY); + + // KEEP: Multiplicative and division operators (*2, /2) + if (match(MUL) || match(DIV)) { + Token operator = consume(); + + // Handle *2, /2, *stepVar, /stepVar + if (match(INT_LIT) || match(FLOAT_LIT) || match(ID) || match(PLUS) || match(MINUS)) { + ExprNode operand = expressionParser.parseExpression(); + // Create a binary operation like i * 2 or i / 2 + ExprNode iteratorRef = ASTFactory.createIdentifier(iterator); + step = ASTFactory.createBinaryOp(iteratorRef, operator.text, operand); + } else { + throw new ParseError("Expected number or variable after " + operator.text, + currentToken().line, currentToken().column); + } + } + // KEEP: Additive operators with optional sign + else if (match(PLUS) || match(MINUS)) { + Token operator = consume(); + + if (peek(0).type == INT_LIT || peek(0).type == FLOAT_LIT) { + // Handle +1, -2, etc. + ExprNode operand = expressionParser.parsePrimaryExpression(); + if (operator.symbol == PLUS) { + step = operand; // Just the number (e.g., 1) + } else { + // Create unary negative (e.g., -2) + step = ASTFactory.createUnaryOp("-", operand); + } + } else { + // Just a simple expression (could be variable) + step = expressionParser.parseExpression(); + } + } + // Simple numeric or variable step + else { + step = expressionParser.parseExpression(); + } + + consumeKeyword(IN); + } else { + step = null; + consumeKeyword(IN); + } + + ExprNode start = expressionParser.parseExpression(); + consumeKeyword(TO); + ExprNode end = expressionParser.parseExpression(); + + RangeNode range = ASTFactory.createRange(step, start, end); + ForNode forNode = ASTFactory.createFor(iterator, range); + + consume(LBRACE); + while (!match(RBRACE)) forNode.body.statements.add(parseStatement()); + consume(RBRACE); + return forNode; + } + + private StmtNode parseOutputStatement() { + consumeKeyword(OUTPUT); + OutputNode output = ASTFactory.createOutput(); + output.arguments.add(expressionParser.parseExpression()); + return output; + } + + private StmtNode parseInputAssignment() { + Token startToken = currentToken(); + String varName = consume(ID).text; + consume(ASSIGN); + String type; + if (match(LPAREN)) { + consume(LPAREN); + type = parseTypeReference(); + consume(RPAREN); + } else { + throw new ParseError( + "Input assignment requires an explicit type grouping, e.g., var = (int)input", + startToken.line, + startToken.column); + } + consumeKeyword(INPUT); + InputNode input = ASTFactory.createInput(type, varName); + return input; + } + + private StmtNode parseExitStatement() { + consumeKeyword(EXIT); + ExitNode exit = ASTFactory.createExit(); + return exit; + } + + private StmtNode parseReturnSlotAssignment() { + List varNames = parseIdList(); + + // Accept both = and := for return slot assignment + if (match(DOUBLE_COLON_ASSIGN)) { + consume(DOUBLE_COLON_ASSIGN); + } else { + consume(ASSIGN); + } + + List slotNames = expressionParser.parseReturnSlots(); + consume(COLON); + MethodCallNode methodCall = expressionParser.parseMethodCall(); + methodCall.slotNames = slotNames; + + // Validate variable names (allow underscore for discard) + for (String varName : varNames) { + if ("_".equals(varName)) { + continue; // Underscore is allowed here - it means discard this slot + } + // Validate other names normally + } + + if (varNames.size() != slotNames.size()) { + throw new ParseError( + "Number of variables (" + varNames.size() + ") does not match number of slots (" + slotNames.size() + ")"); + } + + ReturnSlotAssignmentNode assignment = ASTFactory.createReturnSlotAssignment(varNames, methodCall); + return assignment; +} + + private StmtNode parseIndexAssignment() { + ExprNode arrayVar = ASTFactory.createIdentifier(consume(ID).text); + + IndexAccessNode indexAccess = expressionParser.parseIndexAccessContinuation(arrayVar); + while (match(LBRACKET)) { + indexAccess = expressionParser.parseIndexAccessContinuation(indexAccess); + } + consume(ASSIGN); + ExprNode value = expressionParser.parseExpression(); + AssignmentNode assignment = ASTFactory.createAssignment(indexAccess, value); + return assignment; + } + + private StmtNode parseMethodCallStatement() { + if (isSymbolAt(0, LBRACKET)) { + List slotNames = expressionParser.parseReturnSlots(); + consume(COLON); + MethodCallNode methodCall = expressionParser.parseMethodCall(); + methodCall.slotNames = slotNames; + return methodCall; + } else { + MethodCallNode methodCall = expressionParser.parseMethodCall(); + return methodCall; + } + } + + private StmtNode parseExpressionStatement() { + ExprNode expr = expressionParser.parseExpression(); + return expr; + } + + private List parseIdList() { + List ids = new ArrayList(); + ids.add(consume(ID).text); + while (tryConsume(COMMA)) ids.add(consume(ID).text); + return ids; + } + + // --- Lookahead Methods (OPTIMIZED) --- + + protected boolean isSlotAssignment() { + Token first = lookahead(0); + if (first == null || first.symbol != TILDE_ARROW) return false; + + Token next = lookahead(1); + if (next == null) return false; + + // Check if the next token is a possible start of an expression/literal + return isExpressionStart(next); + } + + // SIMPLIFIED: Uses simpler token-based lookahead instead of complex loop and exception catching + private boolean isIndexAssignment() { + Token first = lookahead(0); + Token second = lookahead(1); + + if (first == null || first.type == ID) { + // Continue to next + } else { + return false; + } + + if (second == null || second.symbol != LBRACKET) return false; + + // REMOVED: Case 1 (Empty brackets) check. + // Now only checks if it looks like an index access (name[...) + + // Case 2: Index access: name[expr]... = value + int pos = getPosition() + 2; // Start after ID [ + int bracketDepth = 1; + + // Look for the matching closing bracket for the first index + while (pos < tokens.size() && bracketDepth > 0) { + Token t = tokens.get(pos); + if (t.symbol == LBRACKET) bracketDepth++; + else if (t.symbol == RBRACKET) bracketDepth--; + pos++; + } + + // If we found a matching bracket + if (bracketDepth == 0) { + // Check for subsequent index accesses or assignment + while (pos < tokens.size() && tokens.get(pos).symbol == LBRACKET) { + pos++; + bracketDepth = 1; + while (pos < tokens.size() && bracketDepth > 0) { + Token t = tokens.get(pos); + if (t.symbol == LBRACKET) bracketDepth++; + else if (t.symbol == RBRACKET) bracketDepth--; + pos++; + } + if (bracketDepth != 0) return false; + } + return pos < tokens.size() && tokens.get(pos).symbol == ASSIGN; + } + + return false; + } + +private boolean isReturnSlotAssignment() { + int p = getPosition(); + + // 1. Variable list (ID, ID...) + Token t = tokens.get(p++); + if (t.type != ID) return false; + + while (p < tokens.size() && tokens.get(p).symbol == COMMA) { + p++; // Skip comma + if (p >= tokens.size() || tokens.get(p).type != ID) return false; + p++; // Skip ID + } + + // 2. Assignment ( = OR := ) + if (p >= tokens.size()) return false; + + // --- FIX START: Allow both ASSIGN and DOUBLE_COLON_ASSIGN --- + if (tokens.get(p).symbol != ASSIGN && tokens.get(p).symbol != DOUBLE_COLON_ASSIGN) return false; + // --- FIX END --- + + p++; + + // 3. Slot list ([...]) + if (p >= tokens.size() || tokens.get(p).symbol != LBRACKET) return false; + p++; + + // Check for at least one slot + if (p >= tokens.size()) return false; + Token firstSlot = tokens.get(p); + if (firstSlot.type == ID || firstSlot.type == INT_LIT) { + p++; + } else if (firstSlot.symbol != RBRACKET) { + return false; + } + + while (p < tokens.size() && tokens.get(p).symbol == COMMA) { + p++; + if (p >= tokens.size()) return false; + Token nextSlot = tokens.get(p); + if (nextSlot.type == ID || nextSlot.type == INT_LIT) { + p++; + } else { + return false; + } + } + + if (p >= tokens.size() || tokens.get(p).symbol != RBRACKET) return false; + p++; + + // 4. Colon (:) + return p < tokens.size() && tokens.get(p).symbol == COLON; +} + + // Original logic was sufficient, minor cleanup + private boolean isInputAssignment() { + int p = getPosition(); + + if (tokens.get(p++).type != ID) return false; + if (p >= tokens.size() || tokens.get(p).symbol != ASSIGN) return false; + p++; + if (p >= tokens.size() || tokens.get(p).symbol != LPAREN) return false; + p++; + + int parenBalance = 1; + while (p < tokens.size() && parenBalance > 0) { + Token t = tokens.get(p); + if (t.symbol == LPAREN) parenBalance++; + else if (t.symbol == RPAREN) parenBalance--; + p++; + } + + if (parenBalance != 0) return false; // Type grouping must close + + return p < tokens.size() && isKeywordAt(p - getPosition(), INPUT); + } + + // Original logic was sufficient, minor cleanup + private boolean isMethodCallStatement() { + int p = getPosition(); + + if (isSymbolAt(0, LBRACKET)) { + // Check for [slots] : call() + p++; + if (p >= tokens.size() || (tokens.get(p).type != ID && tokens.get(p).type != INT_LIT)) + return false; + p++; + while (p < tokens.size() && tokens.get(p).symbol == COMMA) { + p++; + if (p >= tokens.size() || (tokens.get(p).type != ID && tokens.get(p).type != INT_LIT)) + return false; + p++; + } + if (p >= tokens.size() || tokens.get(p).symbol != RBRACKET) return false; + p++; + if (p >= tokens.size() || tokens.get(p).symbol != COLON) return false; + p++; + } + + // Check for qualified name/ID + if (p >= tokens.size() || tokens.get(p).type != ID) return false; + p++; + while (p < tokens.size() && tokens.get(p).symbol == DOT) { + p++; + if (p >= tokens.size() || tokens.get(p).type != ID) return false; + p++; + } + + // Must be followed by ( + return p < tokens.size() && tokens.get(p).symbol == LPAREN; + } + +private boolean isVariableDeclaration() { + Token first = lookahead(0); + Token second = lookahead(1); + + if (first == null) return false; + + // Case 1: name := value (implicit typing) + if (first.type == ID && second != null && second.symbol == DOUBLE_COLON_ASSIGN) { + return true; + } + + // Case 2: name: type or name: type = value + if (first.type == ID && second != null && second.symbol == COLON) { + int pos = getPosition() + 2; // Skip ID and COLON + if (pos < tokens.size()) { + Token third = tokens.get(pos); + return isTypeStart(third); + } + } + + return false; +} +} \ No newline at end of file From 0c260ad8a6b7637e73bc8c8ed24ae23dcfcdee11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:35:19 +0800 Subject: [PATCH 40/54] Create MainLexer.java --- src/main/java/cod/lexer/MainLexer.java | 415 +++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 src/main/java/cod/lexer/MainLexer.java diff --git a/src/main/java/cod/lexer/MainLexer.java b/src/main/java/cod/lexer/MainLexer.java new file mode 100644 index 00000000..5403f505 --- /dev/null +++ b/src/main/java/cod/lexer/MainLexer.java @@ -0,0 +1,415 @@ +package cod.lexer; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static cod.syntax.Keyword.*; +import cod.syntax.Symbol; +import static cod.syntax.Symbol.*; + +public class MainLexer { + + public enum TokenType { + KEYWORD, + INT_LIT, + FLOAT_LIT, + STRING_LIT, + BOOL_LIT, + ID, + SYMBOL, + EOF, + INVALID, + LINE_COMMENT, + BLOCK_COMMENT, + WS; + } + + public static class Token { + public final TokenType type; + public final String text; + public final int line; + public final int column; + public final Symbol symbol; + + public Token(TokenType type, String text, int line, int column) { + this.type = type; + this.text = text; + this.line = line; + this.column = column; + this.symbol = null; + } + + public Token(TokenType type, String text, int line, int column, Symbol symbol) { + this.type = type; + this.text = text; + this.line = line; + this.column = column; + this.symbol = symbol; + } + + @Override + public String toString() { + return "Token{" + + "type=" + type.name() + + ", text='" + text + '\'' + + (symbol != null ? ", symbol=" + symbol.name() : "") + + ", line=" + line + + ", column=" + column + + '}'; + } + } + + private static final Set KEYWORDS = new HashSet(); + + static { + for (cod.syntax.Keyword keyword : cod.syntax.Keyword.values()) { + KEYWORDS.add(keyword.toString()); + } + } + + private final String input; + private int position = 0; + private int line = 1; + private int column = 1; + + public MainLexer(String input) { + this.input = input; + } + + public List tokenize() { + List tokens = new ArrayList(); + while (position < input.length()) { + skipWhitespaceAndComments(); + if (position < input.length()) { + tokens.add(scanNextToken()); + } + } + tokens.add(create(TokenType.EOF)); + return tokens; + } + + private void skipWhitespaceAndComments() { + while (position < input.length()) { + char c = peek(); + if (Character.isWhitespace(c)) { + consume(); + } else if (c == '/' && peek(1) == '/') { + scanLineComment(); + } else if (c == '/' && peek(1) == '*') { + scanBlockComment(); + } else { + break; + } + } + } + + private Token scanNextToken() { + char c = peek(); + + if (Character.isLetter(c) || c == '_') return readIdentifierOrKeyword(); + if (Character.isDigit(c)) return readNumber(); + if (c == '"') return readString(); + return readSymbol(); + } + + private Token readIdentifierOrKeyword() { + StringBuilder sb = new StringBuilder(); + while (position < input.length() && (Character.isLetterOrDigit(peek()) || peek() == '_')) { + sb.append(consume()); + } + String text = sb.toString(); + + if (KEYWORDS.contains(text)) { + return create(TokenType.KEYWORD, text); + } + + return create(TokenType.ID, text); + } + + private Token readNumber() { + StringBuilder sb = new StringBuilder(); + boolean isFloat = false; + + // 1. Read integer part + while (position < input.length() && Character.isDigit(peek())) { + sb.append(consume()); + } + + // 2. Read fractional part + if (peek() == '.') { + isFloat = true; + sb.append(consume()); + while (position < input.length() && Character.isDigit(peek())) { + sb.append(consume()); + } + } + + // 3. Read Numeric Shorthand Suffix (K, M, Qi, etc.) + String suffix = readSuffix(); + if (!suffix.isEmpty()) { + sb.append(suffix); + isFloat = true; + } else { + // 4. NEW: Read Standard Scientific Notation (e/E) + String exponent = readExponent(); + if (!exponent.isEmpty()) { + sb.append(exponent); + isFloat = true; + } + } + + String numberText = sb.toString(); + return create( + isFloat ? TokenType.FLOAT_LIT : TokenType.INT_LIT, numberText); +} + +// NEW Helper method for MainLexer (Numeric Shorthands) +private String readSuffix() { + if (position >= input.length()) return ""; + + char c1 = peek(); + + // Check custom suffixes (Case sensitive) + if (c1 == 'K' || c1 == 'M' || c1 == 'B' || c1 == 'T') { + return String.valueOf(consume()); + } + + if (c1 == 'Q') { + consume(); // consume Q + if (peek() == 'i') { + consume(); // consume i + return "Qi"; + } + return "Q"; + } + + return ""; +} + +// NEW Helper method to read the standard 'e' exponent part (Case insensitive) +private String readExponent() { + if (position >= input.length()) return ""; + + char c1 = peek(); + if (c1 != 'e' && c1 != 'E') { + return ""; + } + + StringBuilder sb = new StringBuilder(); + sb.append(consume()); // Consume 'e' or 'E' + + // Consume optional sign (+ or -) + char c2 = peek(); + if (c2 == '+' || c2 == '-') { + sb.append(consume()); + } + + // Must be followed by at least one digit + if (position < input.length() && Character.isDigit(peek())) { + while (position < input.length() && Character.isDigit(peek())) { + sb.append(consume()); + } + } else { + // If 'e' or 'E' is not followed by a digit (after optional sign), + // backtrack the 'e' or 'E' and treat it as part of identifier/error. + // NOTE: In a complete Lexer, this should rollback position, but for simplicity here, + // we'll stop the number read and rely on the parser to handle the trailing characters if any. + // Since this is the end of readNumber, any non-digit following 'e' will be part of the ID logic. + // Given your current Lexer structure, we must ensure 'e' is followed by a digit. + if (sb.length() == 1 || (sb.length() == 2 && (sb.charAt(1) == '+' || sb.charAt(1) == '-'))) { + // We only consumed 'e' or 'e+' / 'e-', but no digit followed. This is invalid scientific notation. + // We return an empty string to signify failure, but a real Lexer needs error handling/backtracking. + // For safety, we'll assume a digit must follow for it to be an exponent. + return ""; + } + } + + return sb.toString(); +} + + private Token readString() { + StringBuilder sb = new StringBuilder(); + consume(); // Consume opening quote + while (position < input.length() && peek() != '"') { + if (peek() == '\\') { + consume(); // consume the backslash + char escaped = consume(); + switch (escaped) { + case 'n': sb.append('\n'); break; + case 't': sb.append('\t'); break; + case 'r': sb.append('\r'); break; + case '\\': sb.append('\\'); break; + case '"': sb.append('"'); break; + default: sb.append('\\').append(escaped); break; + } + } else { + sb.append(consume()); + } + } + if (position < input.length()) consume(); // Consume closing quote + return create(TokenType.STRING_LIT, sb.toString()); + } + + private Token readSymbol() { + char c1 = consume(); + switch (c1) { + // NEW: Pipe support for Union Types (int|text) + case '|': + return create(PIPE, "|"); + + // NEW: Ampersand support + case '&': + return create(AMPERSAND, "&"); + + // UPDATED: Added := operator + case ':': + if (peek() == '=') { + consume(); + return create(DOUBLE_COLON_ASSIGN, ":="); + } else if (peek() == ':') { + consume(); + return create(DOUBLE_COLON, "::"); + } else { + return create(COLON, ":"); + } + + case '=': + if (peek() == '=') { + consume(); + return create(EQ, "=="); + } else { + return create(ASSIGN, "="); + } + case '>': + if (peek() == '=') { + consume(); + return create(GTE, ">="); + } else { + return create(GT, ">"); + } + case '<': + if (peek() == '=') { + consume(); + return create(LTE, "<="); + } else { + return create(LT, "<"); + } + case '!': + if (peek() == '=') { + consume(); + return create(NEQ, "!="); + } else { + return create(BANG, "!"); + } + case '+': + if (peek() == '=') { + consume(); + return create(PLUS_ASSIGN, "+="); + } else { + return create(PLUS, "+"); + } + case '-': + if (peek() == '=') { + consume(); + return create(MINUS_ASSIGN, "-="); + } else { + return create(MINUS, "-"); + } + case '*': + if (peek() == '=') { + consume(); + return create(MUL_ASSIGN, "*="); + } else { + return create(MUL, "*"); + } + case '/': + if (peek() == '=') { + consume(); + return create(DIV_ASSIGN, "/="); + } else { + return create(DIV, "/"); + } + case '~': + if (peek() == '>') { + consume(); + return create(TILDE_ARROW, "~>"); + } else { + return create(TokenType.INVALID); + } + case '?': + return create(QUESTION, "?"); + case '%': + return create(MOD, "%"); + case '.': + return create(DOT, "."); + case ',': + return create(COMMA, ","); + case '(': + return create(LPAREN, "("); + case ')': + return create(RPAREN, ")"); + case '{': + return create(LBRACE, "{"); + case '}': + return create(RBRACE, "}"); + case '[': + return create(LBRACKET, "["); + case ']': + return create(RBRACKET, "]"); + case '_': + return create(UNDERSCORE, "_"); + default: + return create(TokenType.INVALID); + } + } + + private Token create(TokenType type, String text) { + return new Token(type, text, this.line, this.column); + } + + private Token create(TokenType type) { + return new Token(type, type.name().toLowerCase(), this.line, this.column); + } + + private Token create(Symbol symbol, String text) { + return new Token(TokenType.SYMBOL, text, this.line, this.column, symbol); + } + + private void scanLineComment() { + while (position < input.length() && peek() != '\n') consume(); + } + + private void scanBlockComment() { + consume(); + consume(); // consume '/*' + while (position < input.length() - 1) { + if (peek() == '*' && peek(1) == '/') { + consume(); + consume(); + return; + } + consume(); + } + } + + private char peek() { + return peek(0); + } + + private char peek(int offset) { + return (position + offset >= input.length()) ? '\0' : input.charAt(position + offset); + } + + private char consume() { + char c = input.charAt(position++); + if (c == '\n') { + line++; + column = 1; + } else { + column++; + } + return c; + } +} From 3a8b7ef4a8c01b895b1ce347105ffb8a836c94ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:36:34 +0800 Subject: [PATCH 41/54] Create Symbol.java --- src/main/java/cod/syntax/Symbol.java | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/cod/syntax/Symbol.java diff --git a/src/main/java/cod/syntax/Symbol.java b/src/main/java/cod/syntax/Symbol.java new file mode 100644 index 00000000..d93e795f --- /dev/null +++ b/src/main/java/cod/syntax/Symbol.java @@ -0,0 +1,40 @@ +package cod.syntax; + +public enum Symbol { + EQ, + ASSIGN, + GT, + GTE, + LT, + LTE, + NEQ, + BANG, + + PLUS, + PLUS_ASSIGN, + MINUS, + MINUS_ASSIGN, + MUL, + MUL_ASSIGN, + DIV, + DIV_ASSIGN, + + MOD, + DOUBLE_COLON, + DOUBLE_COLON_ASSIGN, + TILDE_ARROW, + COLON, + DOT, + COMMA, + LPAREN, + RPAREN, + LBRACE, + RBRACE, + LBRACKET, + RBRACKET, + + PIPE, + QUESTION, + AMPERSAND, + UNDERSCORE +} From 27bf5b8083f44bcec57140ab5ed80beefe35d172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:47:43 +0800 Subject: [PATCH 42/54] Add files via upload --- src/main/java/cod/syntax/Keyword.java | 84 +++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/main/java/cod/syntax/Keyword.java diff --git a/src/main/java/cod/syntax/Keyword.java b/src/main/java/cod/syntax/Keyword.java new file mode 100644 index 00000000..a38b397f --- /dev/null +++ b/src/main/java/cod/syntax/Keyword.java @@ -0,0 +1,84 @@ +package cod.syntax; + +/** * + * This enum contains all of the keywords + * for the Coderive language. + * + * **/ +public enum Keyword { + + // Visibility modifiers + SHARE, + LOCAL, + + // namespace + UNIT, + + // import + USE, + + // extends & instanceof + IS, + + THIS, + INPUT, + OUTPUT, + IF, + ELSE, + ELIF, + + // Loop + FOR, + BREAK, + CONTINUE, + + // Used in loop and natural arrays + IN, + TO, + BY, + + // Primitive types + INT, + TEXT, + FLOAT, + BOOL, + + BUILTIN, + + + ALL, + ANY, + + EXIT, + + NULL, + TRUE, + FALSE, + + // For more control and auto wrappings of variables + GET, + SET, + + // Keyword for converting between safe and unsafe states + CONTROL, + + // Toggle strictly after visibility modifier to be able to use unsafe primitives and do low level operations + UNSAFE, + + // Unsafe primitives (for low-level operations) + I8, + I16, + I32, + I64, + U8, + U16, + U32, + U64, + F32, + F64; + + @Override + public String toString() { + return name().toLowerCase(); + } +} \ No newline at end of file From 72721ceff42a0ad114e3f0970e66a9fde7c76fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:49:23 +0800 Subject: [PATCH 43/54] Create ImportResolver.java --- .../java/cod/semantic/ImportResolver.java | 317 ++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 src/main/java/cod/semantic/ImportResolver.java diff --git a/src/main/java/cod/semantic/ImportResolver.java b/src/main/java/cod/semantic/ImportResolver.java new file mode 100644 index 00000000..101c9f61 --- /dev/null +++ b/src/main/java/cod/semantic/ImportResolver.java @@ -0,0 +1,317 @@ +package cod.semantic; + +import cod.ast.nodes.*; + +import cod.lexer.MainLexer; +import cod.parser.MainParser; + +import cod.debug.DebugSystem; +import java.util.*; +import java.io.*; + +public class ImportResolver { + private Map importedUnits = new HashMap<>(); + private Map loadedPrograms = new HashMap<>(); + private Map preloadedImports = new HashMap<>(); + private Set registeredImports = new HashSet<>(); + private List importPaths = new ArrayList<>(); + + public ImportResolver() { + // Initialize with default import paths + importPaths.add("."); + importPaths.add("./lib"); + importPaths.add("./imports"); + } + + public void addImportPath(String path) { + importPaths.add(path); + DebugSystem.debug("IMPORTS", "Added import path: " + path); + } + + public void registerImport(String importName) { + // Just store the import name for later resolution + if (!registeredImports.contains(importName)) { + registeredImports.add(importName); + DebugSystem.debug("IMPORTS", "Registered import (lazy): " + importName); + } + } + + public ProgramNode resolveImport(String importName) throws Exception { + DebugSystem.debug("IMPORTS", "resolveImport called for: " + importName); + + // Debug file system first + debugFileSystem(importName); + + // Check if already loaded + if (loadedPrograms.containsKey(importName)) { + DebugSystem.debug("IMPORTS", "Import already loaded: " + importName); + return loadedPrograms.get(importName); + } + + // Check if preloaded during AST building + if (preloadedImports.containsKey(importName)) { + DebugSystem.debug("IMPORTS", "Using preloaded import: " + importName); + ProgramNode program = preloadedImports.get(importName); + loadedPrograms.put(importName, program); + importedUnits.put(importName, program); // Also add to importedUnits for compatibility + return program; + } + + List attemptedPaths = new ArrayList<>(); + ProgramNode program = null; + + // Try different file paths and extensions + String[] basePaths = { + "", // current directory + "cod/", + "src/cod/", + "../cod/", + "/storage/emulated/0/JavaNIDE/Programming-Language/Coderive/executables/" + }; + + String[] extensions = { + ".cod", + ".txt", + "" + }; + + // Convert import name to file path (e.g., "cod.Sys" -> "cod/Sys") + String filePath = importName.replace('.', '/'); + + for (String basePath : basePaths) { + for (String extension : extensions) { + String fullPath = basePath + filePath + extension; + attemptedPaths.add(fullPath); + + try { + DebugSystem.debug("IMPORTS", "Trying path: " + fullPath); + program = loadImportFromFile(fullPath); + if (program != null) { + DebugSystem.debug("IMPORTS", "Successfully loaded import from: " + fullPath); + loadedPrograms.put(importName, program); + importedUnits.put(importName, program); // Also add to importedUnits for compatibility + return program; + } + } catch (Exception e) { + DebugSystem.debug("IMPORTS", "Failed to load from " + fullPath + ": " + e.getMessage()); + // Continue to next path + } + } + } + + // UPDATED: Better error message but still throw + if (program == null) { + String error = "Import not found: " + importName + + " (searched: " + attemptedPaths + ")"; + DebugSystem.error("IMPORTS", error); + throw new RuntimeException(error); + } + + return program; + } + + private ProgramNode loadImportFromFile(String filePath) throws Exception { + File file = new File(filePath); + if (!file.exists() || !file.isFile()) { + return null; + } + + DebugSystem.debug("IMPORTS", "Loading import from file: " + filePath); + + try { + // Read the file content + StringBuilder content = new StringBuilder(); + BufferedReader reader = new BufferedReader(new FileReader(file)); + String line; + while ((line = reader.readLine()) != null) { + content.append(line).append("\n"); + } + reader.close(); + + DebugSystem.debug("IMPORTS", "File content length: " + content.length() + " characters"); + + // Use the SAME MANUAL parser that we use for the main file + MainLexer lexer = new MainLexer(content.toString()); + List tokens = lexer.tokenize(); + + DebugSystem.debug("IMPORTS", "Generated " + tokens.size() + " tokens"); + + MainParser parser = new MainParser(tokens); + ProgramNode program = parser.parseProgram(); + + DebugSystem.debug("IMPORTS", "Successfully parsed import file using manual parser: " + filePath); + return program; + + } catch (Exception e) { + DebugSystem.error("IMPORTS", "Failed to parse import file: " + filePath + " - " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Failed to parse import file: " + filePath + " - " + e.getMessage(), e); + } + } + + public MethodNode findMethod(String qualifiedMethodName) { + DebugSystem.debug("IMPORTS", "findMethod called for: " + qualifiedMethodName); + + // Extract method name and potential import name + int lastDot = qualifiedMethodName.lastIndexOf('.'); + if (lastDot == -1) { + DebugSystem.debug("IMPORTS", "No dots in method name, not an imported method"); + return null; // Not an imported method + } + + String methodName = qualifiedMethodName.substring(lastDot + 1); + String calledImport = qualifiedMethodName.substring(0, lastDot); // This is "Sys" from "Sys.outln" + + DebugSystem.debug("IMPORTS", "Called import part: '" + calledImport + "', method: '" + methodName + "'"); + + // FIX: First check if we already have a loaded import that matches + String actualImportName = null; + + // Check loaded imports first + for (String loadedImport : loadedPrograms.keySet()) { + DebugSystem.debug("IMPORTS", "Checking loaded import: " + loadedImport); + + // Check if loaded import ends with the called import + // e.g., "cod.Sys" ends with ".Sys" and calledImport is "Sys" + if (loadedImport.endsWith("." + calledImport) || loadedImport.equals(calledImport)) { + actualImportName = loadedImport; + DebugSystem.debug("IMPORTS", "Found matching loaded import: " + actualImportName); + break; + } + } + + // If not found in loaded imports, check registered imports + if (actualImportName == null) { + for (String registeredImport : registeredImports) { + DebugSystem.debug("IMPORTS", "Checking registered import: " + registeredImport); + + // Check if registered import ends with the called import + if (registeredImport.endsWith("." + calledImport) || registeredImport.equals(calledImport)) { + actualImportName = registeredImport; + DebugSystem.debug("IMPORTS", "Found matching registered import: " + actualImportName); + break; + } + } + } + + // If still not found, use the called import as-is + if (actualImportName == null) { + actualImportName = calledImport; + DebugSystem.debug("IMPORTS", "No import matched, using: " + actualImportName); + } + + DebugSystem.debug("IMPORTS", "Final import to resolve: '" + actualImportName + "', method: '" + methodName + "'"); + + // Try to resolve the import if not already loaded + if (!loadedPrograms.containsKey(actualImportName)) { + DebugSystem.debug("IMPORTS", "Import not loaded, trying to resolve: " + actualImportName); + try { + ProgramNode program = resolveImport(actualImportName); + if (program != null) { + loadedPrograms.put(actualImportName, program); + importedUnits.put(actualImportName, program); + registeredImports.remove(actualImportName); + DebugSystem.debug("IMPORTS", "Successfully loaded import: " + actualImportName); + } + } catch (Exception e) { + DebugSystem.error("IMPORTS", "Failed to load import " + actualImportName + ": " + e.getMessage()); + return null; + } + } + + // Search through loaded programs for the method + DebugSystem.debug("IMPORTS", "Searching for method '" + methodName + "' in loaded program: " + actualImportName); + + ProgramNode program = loadedPrograms.get(actualImportName); + if (program != null && program.unit != null && program.unit.types != null) { + for (TypeNode type : program.unit.types) { + DebugSystem.debug("IMPORTS", " Searching in type: " + type.name); + + for (MethodNode method : type.methods) { + DebugSystem.debug("IMPORTS", " Checking method: " + method.name); + if (method.name.equals(methodName)) { + DebugSystem.debug("IMPORTS", " *** FOUND METHOD: " + method.name + " ***"); + return method; + } + } + } + } + + // Method not found + DebugSystem.error("IMPORTS", "*** METHOD NOT FOUND: " + qualifiedMethodName + " ***"); + DebugSystem.debug("IMPORTS", "Loaded imports: " + loadedPrograms.keySet()); + DebugSystem.debug("IMPORTS", "Registered imports: " + registeredImports); + + return null; + } + + public void debugFileSystem(String importName) { + DebugSystem.debug("FILE_SYSTEM", "=== FILE SYSTEM DEBUG for: " + importName + " ==="); + + String filePath = importName.replace('.', '/') + ".cod"; + DebugSystem.debug("FILE_SYSTEM", "Looking for: " + filePath); + DebugSystem.debug("FILE_SYSTEM", "Import paths: " + importPaths); + + for (String basePath : importPaths) { + File file = new File(basePath, filePath); + DebugSystem.debug("FILE_SYSTEM", "Path: " + file.getAbsolutePath() + + " [exists: " + file.exists() + ", isFile: " + file.isFile() + "]"); + + // Also check the directory + File dir = file.getParentFile(); + if (dir != null && dir.exists()) { + DebugSystem.debug("FILE_SYSTEM", "Directory contents of " + dir.getAbsolutePath() + ":"); + String[] files = dir.list(); + if (files != null) { + for (String f : files) { + DebugSystem.debug("FILE_SYSTEM", " - " + f); + } + } + } + } + DebugSystem.debug("FILE_SYSTEM", "=== END FILE SYSTEM DEBUG ==="); + } + + public void debugImportStatus() { + DebugSystem.debug("IMPORTS", "=== IMPORT RESOLVER STATUS ==="); + DebugSystem.debug("IMPORTS", "Import paths: " + importPaths); + DebugSystem.debug("IMPORTS", "Loaded imports: " + importedUnits.keySet()); + DebugSystem.debug("IMPORTS", "Registered imports (lazy): " + registeredImports); + + for (Map.Entry entry : importedUnits.entrySet()) { + String unitName = entry.getKey(); + ProgramNode program = entry.getValue(); + DebugSystem.debug("IMPORTS", "Unit: " + unitName); + if (program != null && program.unit != null && program.unit.types != null) { + for (TypeNode type : program.unit.types) { + DebugSystem.debug("IMPORTS", " Type: " + type.name); + for (MethodNode method : type.methods) { + DebugSystem.debug( + "IMPORTS", + " Method: " + + method.name + + " (params: " + + method.parameters.size() + + ")"); + } + } + } + } + DebugSystem.debug("IMPORTS", "=== END IMPORT STATUS ==="); + } + + public void preloadImport(String qualifiedName, ProgramNode program) { + importedUnits.put(qualifiedName, program); + loadedPrograms.put(qualifiedName, program); + preloadedImports.put(qualifiedName, program); + DebugSystem.debug("IMPORTS", "Pre-loaded import into resolver: " + qualifiedName); + } + + public Set getLoadedImports() { + return importedUnits.keySet(); + } + + public Set getRegisteredImports() { + return new HashSet<>(registeredImports); + } +} From ae11c678ef186b1b0d75d793b2e793c8ca8914c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:49:46 +0800 Subject: [PATCH 44/54] Add files via upload --- .../java/cod/semantic/NamingValidator.java | 83 ++++++++ .../java/cod/semantic/ProgramValidator.java | 196 ++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 src/main/java/cod/semantic/NamingValidator.java create mode 100644 src/main/java/cod/semantic/ProgramValidator.java diff --git a/src/main/java/cod/semantic/NamingValidator.java b/src/main/java/cod/semantic/NamingValidator.java new file mode 100644 index 00000000..bd460001 --- /dev/null +++ b/src/main/java/cod/semantic/NamingValidator.java @@ -0,0 +1,83 @@ +package cod.semantic; + +import cod.error.ParseError; +import cod.lexer.MainLexer.Token; + +public class NamingValidator { + + public static void validateClassName(String name, Token token) { + if (!isPascalCase(name)) { + throw new ParseError( + "Class name '" + name + "' must use PascalCase (start with uppercase letter)", + token.line, token.column + ); + } + } + + public static void validateMethodName(String name, Token token) { + if (!startsWithLowerCase(name)) { + throw new ParseError( + "Method name '" + name + "' must start with lowercase letter", + token.line, token.column + ); + } + } + +public static void validateVariableName(String name, Token token) { + // REJECT underscore as variable name (only parameter, not variable) + if ("_".equals(name)) { + throw new ParseError( + "Underscore '_' is reserved for discard/placeholder in parameters and cannot be used as a variable name", + token.line, token.column + ); + } + + if (isPascalCase(name)) { + throw new ParseError( + "Variable/parameter name '" + name + "' cannot use PascalCase (reserved for classes). " + + "Use camelCase, snake_case, or ALL_CAPS instead", + token.line, token.column + ); + } +} + + +public static void validateParameterName(String name, Token token) { + // ALLOW underscore as parameter name + if ("_".equals(name)) { + return; // Valid as parameter name (means discard) + } + + if (isPascalCase(name)) { + throw new ParseError( + "Parameter name '" + name + "' cannot use PascalCase (reserved for classes). " + + "Use camelCase, snake_case, or ALL_CAPS instead", + token.line, token.column + ); + } +} + + public static void validateConstantName(String name, Token token) { + if (!isAllCaps(name)) { + throw new ParseError( + "Constant name '" + name + "' must use ALL_CAPS with underscores", + token.line, token.column + ); + } + } + + public static boolean isPascalCase(String name) { + return name != null && !name.isEmpty() && + Character.isUpperCase(name.charAt(0)) && + !isAllCaps(name); + } + + public static boolean startsWithLowerCase(String name) { + return name != null && !name.isEmpty() && + Character.isLowerCase(name.charAt(0)); + } + + public static boolean isAllCaps(String name) { + return name != null && name.matches("[A-Z0-9_]+"); + } +} \ No newline at end of file diff --git a/src/main/java/cod/semantic/ProgramValidator.java b/src/main/java/cod/semantic/ProgramValidator.java new file mode 100644 index 00000000..7b853ed9 --- /dev/null +++ b/src/main/java/cod/semantic/ProgramValidator.java @@ -0,0 +1,196 @@ +package cod.semantic; + +import cod.ast.nodes.*; +import cod.parser.ProgramType; +import cod.error.ParseError; + +/** + * Validates that a program conforms to the rules of its detected program type. + * Enforces the three-worlds design: + * - SCRIPT: Only statements, no methods, no classes + * - METHOD_SCRIPT: Only methods, no direct code, no classes + * - MODULE: Unit + Classes only, no direct code outside methods + */ +public class ProgramValidator { + + /** + * Validates the entire program against its detected program type. + * + * @param program The program to validate + * @param programType The detected program type + * @throws ParseError if validation fails + */ + public static void validate(ProgramNode program, ProgramType programType) { + if (program == null) { + throw new ParseError("Program cannot be null"); + } + + switch (programType) { + case MODULE: + validateModule(program); + break; + case SCRIPT: + validateScript(program); + break; + case METHOD_SCRIPT: + validateMethodScript(program); + break; + default: + throw new ParseError("Unknown program type: " + programType); + } + } + + /** + * Validates a MODULE program. + * Rules: + * 1. Must have unit declaration + * 2. Must contain at least one class + * 3. Cannot have direct code outside classes + * 4. Cannot have methods outside classes + */ + private static void validateModule(ProgramNode program) { + // Rule 1: Must have unit declaration (not "default") + if (program.unit == null || "default".equals(program.unit.name)) { + throw new ParseError( + "Module must start with 'unit' declaration.\n" + + "Add: unit namespace.name\n" + + "Before your class definitions." + ); + } + + // Rule 2: Must contain at least one class + if (program.unit.types == null || program.unit.types.isEmpty()) { + throw new ParseError( + "Module '" + program.unit.name + "' must contain at least one class.\n" + + "Add a class: share ClassName { ... }" + ); + } + + // Rules 3 & 4: Check each class + for (TypeNode type : program.unit.types) { + // Check for direct code in classes + if (type.statements != null && !type.statements.isEmpty()) { + throw new ParseError( + "Modules cannot have direct code outside classes.\n" + + "Move the code inside a method in class '" + type.name + "'." + ); + } + + // Note: Methods in classes are validated by DeclarationParser + } + } + + /** + * Validates a SCRIPT program. + * Rules: + * 1. Can have direct code (statements) + * 2. Cannot have method declarations + * 3. Cannot have class declarations + * 4. Cannot have field declarations + */ + private static void validateScript(ProgramNode program) { + // Scripts are allowed to have imports + // Scripts are parsed into a synthetic class with statements + + // Check each type (should only be the synthetic __Script__ type) + for (TypeNode type : program.unit.types) { + // Rule 2: Cannot have method declarations + if (type.methods != null && !type.methods.isEmpty()) { + throw new ParseError( + "Scripts cannot contain method declarations.\n" + + "Either:\n" + + "1. Remove methods and keep as script, OR\n" + + "2. Remove direct code and make it a method script, OR\n" + + "3. Add 'unit' and classes to make it a module." + ); + } + + // Rule 3: Cannot have real class declarations (synthetic type is OK) + if (!type.name.startsWith("__") && type.name != null) { + // This is a real class name, not allowed in scripts + throw new ParseError( + "Scripts cannot contain class declarations.\n" + + "Found class: " + type.name + "\n" + + "Remove the class or add 'unit' to make it a module." + ); + } + + // Rule 4: Cannot have field declarations + if (type.fields != null && !type.fields.isEmpty()) { + throw new ParseError( + "Scripts cannot contain field declarations.\n" + + "Found fields in type: " + type.name + "\n" + + "Remove field declarations or use variables instead." + ); + } + } + } + + /** + * Validates a METHOD_SCRIPT program. + * Rules: + * 1. Must contain at least one method + * 2. Cannot have direct code outside methods + * 3. Cannot have class declarations + * 4. Cannot have field declarations + * 5. Should have main() method (warning only) + */ +private static void validateMethodScript(ProgramNode program) { + boolean hasMethods = false; + + for (TypeNode type : program.unit.types) { + if (type.methods != null && !type.methods.isEmpty()) { + hasMethods = true; + } + + if (type.statements != null && !type.statements.isEmpty()) { + throw new ParseError( + "Method scripts cannot have direct code outside methods.\n" + + "Place all code inside method declarations." + ); + } + + // Synthetic type name is OK + if (type.name != null && !type.name.startsWith("__")) { + // Check if it's actually a synthetic type created by parser + // If not, it's an error + throw new ParseError( + "Method scripts cannot contain class declarations.\n" + + "Found: " + type.name + "\n" + + "Remove the class or add 'unit' to make it a module." + ); + } + + if (type.fields != null && !type.fields.isEmpty()) { + throw new ParseError( + "Method scripts cannot contain field declarations.\n" + + "Remove field declarations or add 'unit' to make it a module." + ); + } + } + + if (!hasMethods) { + throw new ParseError("Method script must contain at least one method."); + } + + // Warning for missing main() - optional + boolean hasMain = false; + for (TypeNode type : program.unit.types) { + if (type.methods != null) { + for (MethodNode method : type.methods) { + if ("main".equals(method.name)) { + if (method.parameters == null || method.parameters.isEmpty()) { + hasMain = true; + break; + } + } + } + } + if (hasMain) break; + } + + if (!hasMain) { + System.err.println("Warning: Method script should have a 'main()' method"); + } +} +} \ No newline at end of file From ff970e8d0f95e8b4f3e7860fe2505632f6d0fe7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:51:20 +0800 Subject: [PATCH 45/54] Create LexError.java --- src/main/java/cod/error/LexError.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/cod/error/LexError.java diff --git a/src/main/java/cod/error/LexError.java b/src/main/java/cod/error/LexError.java new file mode 100644 index 00000000..fa7679bd --- /dev/null +++ b/src/main/java/cod/error/LexError.java @@ -0,0 +1,8 @@ +package cod.error; + +public class LexError extends RuntimeException { + + public LexError(String message) { + super(message); + } +} From 655e9309ee7c9c35667407e51b616e2b67b5f35d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:51:42 +0800 Subject: [PATCH 46/54] Add files via upload --- src/main/java/cod/error/ParseError.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/java/cod/error/ParseError.java diff --git a/src/main/java/cod/error/ParseError.java b/src/main/java/cod/error/ParseError.java new file mode 100644 index 00000000..6979c32e --- /dev/null +++ b/src/main/java/cod/error/ParseError.java @@ -0,0 +1,24 @@ +package cod.error; + +public class ParseError extends RuntimeException { + private int line; + private int column; + + public ParseError(String message, int line, int column) { + super(message + " at line " + line + ":" + column); + this.line = line; + this.column = column; + } + + public ParseError(String message) { + super(message); + } + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } +} \ No newline at end of file From a136863a1b03336ed484324954a6c7975efa4234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:52:06 +0800 Subject: [PATCH 47/54] Delete src/main/cod/cod directory --- src/main/cod/cod/Math.cod | 56 --------------------------------------- src/main/cod/cod/Sys.cod | 12 --------- 2 files changed, 68 deletions(-) delete mode 100644 src/main/cod/cod/Math.cod delete mode 100644 src/main/cod/cod/Sys.cod diff --git a/src/main/cod/cod/Math.cod b/src/main/cod/cod/Math.cod deleted file mode 100644 index 95be31df..00000000 --- a/src/main/cod/cod/Math.cod +++ /dev/null @@ -1,56 +0,0 @@ -unit cod - -share Math { - - ~| result - share sqrt(float x) { - if x < 0 { - ~> 0 - } elif x == 0 { - ~> 0 - } else { - // Simple square root approximation - float guess = x / 2 - for i in 1 to 10 { - guess = (guess + x / guess) / 2 - } - ~> guess - } - } - - ~| result - share pow(float base, float exponent) { - float temp = 1 - for i in 1 to exponent { - temp = temp * base - } - ~> temp - } - - ~| result - share max(float a, float b) { - if a > b { - ~> a - } else { - ~> b - } - } - - ~| result - share min(float a, float b) { - if a < b { - ~> a - } else { - ~> b - } - } - - ~| result - share abs(float x) { - if x < 0 { - ~> -x - } else { - ~> x - } - } -} \ No newline at end of file diff --git a/src/main/cod/cod/Sys.cod b/src/main/cod/cod/Sys.cod deleted file mode 100644 index 73e4ef92..00000000 --- a/src/main/cod/cod/Sys.cod +++ /dev/null @@ -1,12 +0,0 @@ -unit cod - -share Sys { - -// auto in-between spacing between each + and any other concats -builtin outa(string inp) {} - -share outln(string inp) { -output inp + "\n" -} - -} \ No newline at end of file From ea3d00f8af3753db7c6c58f49675b600a6734197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:52:39 +0800 Subject: [PATCH 48/54] Add files via upload --- src/main/cod/ArrayTest.cod | 99 +++++++--- src/main/cod/EvenOdd.cod | 19 +- src/main/cod/ImportTest.cod | 29 +-- src/main/cod/InteractiveDemo.cod | 300 +++++++++++++---------------- src/main/cod/LoopTest.cod | 19 +- src/main/cod/NaturalArrayTest.cod | 115 +++++++++++ src/main/cod/ParamSkipDemo.cod | 131 +++++++++++++ src/main/cod/PrimitiveTest.cod | 70 +++---- src/main/cod/RecursiveForPrint.cod | 26 ++- src/main/cod/SlotTest.cod | 22 ++- 10 files changed, 542 insertions(+), 288 deletions(-) create mode 100644 src/main/cod/NaturalArrayTest.cod create mode 100644 src/main/cod/ParamSkipDemo.cod diff --git a/src/main/cod/ArrayTest.cod b/src/main/cod/ArrayTest.cod index 5e063a5e..a331dfd4 100644 --- a/src/main/cod/ArrayTest.cod +++ b/src/main/cod/ArrayTest.cod @@ -1,32 +1,67 @@ -unit sample get { - cod.Math -} - -share ArrayTest { - share main() { - // Array declaration and initialization - int[] numbers = [1, 2, 3, 4, 5] - output "Array: " + numbers - - // Array access - output "First element: " + numbers[0] - output "Third element: " + numbers[2] - - // String array - string[] names = ["Alice", "Bob", "Charlie"] - output "Names: " + names - output "Second name: " + names[1] - - // Array assignment - numbers[0] = 100 - output "After assignment - First element: " + numbers[0] - - // Empty array - int[] empty = [] - output "Empty array: " + empty - - // Single element array - int[] single = [42] - output "Single element: " + single[0] - } -} \ No newline at end of file +use { + lang.Sys, + lang.Math +} + +// Test 2 - Should work based on parseTypeReference() output +local test2() :: arr: [int] { + ~> arr: [1, 2, 3] +} + + share main() { + // Array declaration and initialization + numbers: [int] = [1, 2, 3, 4, 5] + Sys.println("Array: " + numbers) + + // Array access + Sys.println("First element: " + numbers[0]) + Sys.println("Third element: " + numbers[2]) + + // String array + names: [text] = ["Alice", "Bob", "Charlie"] + Sys.println("Names: " + names) + Sys.println("Second name: " + names[1]) + + // Array assignment + numbers[0] = 100 + Sys.println("After assignment - First element: " + numbers[0]) + + // Empty array + empty := [] + Sys.println("Empty array: " + empty) + + // Single element array + single: [] = [42] + Sys.println("Single element: " + single[0]) + + x := [1 to 10] + Sys.println("Simple natural array: " + x[2]) + + Sys.println("Big number: " + 9.999Qi) + + x = [by 2 in 168 to 9.999Qi] + Sys.println("Multiplicative natural array: ") + Sys.println("Before mutation: " + x[20000]) + x[20000] = "hello" + Sys.println("After mutation: " + x[20000]) + + x = [[1 to 10]] + Sys.println("Simple nested natural array: " + x[0][2]) + + x = [[1 to 10], [by 2 in 3 to 100]] + Sys.println("Nested natural array: " + x[1][5]) + + x = ["a" to "Zz"] + Sys.println("Alphabet natural array: " + x[52]) + + range := [1 to 10] + container := [range] + Sys.println(range[5]) + Sys.println(container[0][1]) + Sys.println(container[0][5]) + + // Test string formatting + Sys.println("Test: |" + "trailing space " + "|") + Sys.println("Number: " + 40168) + Sys.println(9.999Qi) + } \ No newline at end of file diff --git a/src/main/cod/EvenOdd.cod b/src/main/cod/EvenOdd.cod index 0e0d34b9..696b1550 100644 --- a/src/main/cod/EvenOdd.cod +++ b/src/main/cod/EvenOdd.cod @@ -1,13 +1,12 @@ -share EvenOdd { - share main() { - int number = 5 - output "The number is " + number - if (number % 2) == 0 { - output "The number is even." - } else { - output "The number is odd." - } - } +use { + lang.Sys +} +number := 5 +Sys.outln("The number is " + number) +if (number % 2) == 0 { + Sys.outln("The number is even.") +} else { + Sys.outln("The number is odd.") } \ No newline at end of file diff --git a/src/main/cod/ImportTest.cod b/src/main/cod/ImportTest.cod index 221a11d1..9c69dfea 100644 --- a/src/main/cod/ImportTest.cod +++ b/src/main/cod/ImportTest.cod @@ -1,30 +1,33 @@ -unit sample get { - cod.Math +unit sample + +use { + lang.Sys, + lang.Math } share ImportTest { share testMathOperations() { - output "=== Testing Math Import ===" + Sys.outln("=== Testing Math Import ===") // Test calling imported math functions - sqrtResult = [result]:cod.Math.sqrt(16) - output "Square root of 16: " + sqrtResult + sqrtResult := [0]:Math.sqrt(16) + Sys.outln("Square root of 16: " + sqrtResult) - powResult = [result]:cod.Math.pow(2, 3) - output "2 to the power of 3: " + powResult + powResult := [0]:Math.pow(2, 3) + Sys.outln("2 to the power of 3: " + powResult) - maxResult = [result]:cod.Math.max(10, 20) - output "Maximum of 10 and 20: " + maxResult + maxResult := [0]:Math.max(10, 20) + Sys.outln("Maximum of 10 and 20: " + maxResult) } share main() { - output "=== IMPORT SYSTEM TEST ===" - output "" + Sys.outln("=== IMPORT SYSTEM TEST ===") + Sys.outln("") testMathOperations() - output "" + Sys.outln("") - output "=== TEST COMPLETE ===" + Sys.outln("=== TEST COMPLETE ===") } } \ No newline at end of file diff --git a/src/main/cod/InteractiveDemo.cod b/src/main/cod/InteractiveDemo.cod index 75ac24dd..140619ca 100644 --- a/src/main/cod/InteractiveDemo.cod +++ b/src/main/cod/InteractiveDemo.cod @@ -1,70 +1,78 @@ unit sample -get { - cod.Sys +use { + lang.Sys } share InteractiveDemo { // Supporting both else-if and elif - ~| int formula, string operation - local calculate(int a, int b, string op) { + local calculate(a: int, b: int, op: text) + :: formula: int|float, operation: text { if op == "+" { // Separate return assignments - ~> formula a + b - ~> operation "addition" + ~> formula: a + b + ~> operation: "addition" } else if op == "-" { // One line return assignments - ~> formula a - b, operation "subtraction" + ~> formula: a - b, operation: "subtraction" } else if op == "*" { // implicit one line return assignments ~> a * b, "multiplication" } else if op == "/" { // mixed one line return assignments - ~> formula a / b, "division" + ~> formula: a / b, "division" } else { ~> 0, "unknown" } } // Method with single expression - local add(int a, int b) ~> a + b + local add(a: int, b: int) ~> a + b - // TBA: This should fail the compilation but for now doesn't yet. - ~| x, y - local haha(int a) { + local haha(a: int) :: x: int, y: int { + // Without '~> value' this will make a compile error } // Array demonstration local demonstrateArrays() { - Sys.outln("=== Array Demo ===") + Sys.println("=== Array Demo ===") + + num1: [] = [1, 2, 3] + + Sys.println("Trying num1: [] = " + num1) + + num2: [int] = [2, 3, 4, 5, 6] - numbers = [10, 20, 30, 40, 50] - Sys.outln("Array: " + numbers) + Sys.println("Trying num2: [int] = " + num2) - Sys.outln("First element: " + numbers[0] + " ") - Sys.outa("Last element:" + numbers[4]) // testing output + // With implicitness + num3 := [10, 20, 30, 40, 50] + Sys.println("Trying: num3 := " + num3) - numbers[2] = 99 - Sys.outln("After modification: " + numbers) + Sys.println("First element: " + num3[0]) + Sys.println("Last element: " + num3[4]) + + num3[2] = 99 + Sys.println("After modification: " + num3) } // Input demonstration with ENHANCED VALIDATION local getUserInfo() { - Sys.outln("=== User Registration ===") + Sys.println("=== User Registration ===") - Sys.outln("Enter your name:") - name = (string) input + Sys.println("Enter your name:") + name := (text) input - Sys.outln("Enter your age:") - age = (int) input + Sys.println("Enter your age:") + age := (int) input - Sys.outln("Enter your height (meters):") - height = (float) input + Sys.println("Enter your height (meters):") + height := (float) input - Sys.outln("Are you a student? (true/false)") - isStudent = (bool) input + Sys.println("Are you a student? (true/false)") + isStudent := (bool) input // NEW: Showcasing 'all' for comprehensive validation if all[ @@ -74,276 +82,238 @@ share InteractiveDemo { height > 0.0, height < 3.0 ] { - Sys.outln("") - Sys.outln("Registration Complete!") - Sys.outln("Name: " + name) - Sys.outln("Age: " + age) - Sys.outln("Height: " + height + "m") - Sys.outln("Student: " + isStudent) + Sys.println("") + Sys.println("Registration Complete!") + Sys.println("Name: " + name) + Sys.println("Age: " + age) + Sys.println("Height: " + height + "m") + Sys.println("Student: " + isStudent) // NEW: Showcasing 'any' for role-based greeting if any[isStudent, age < 25] { - Sys.outln("Welcome young user " + name + "!") + Sys.println("Welcome young user " + name + "!") } else { - Sys.outln("Welcome " + name + "!") + Sys.println("Welcome " + name + "!") } } else { - Sys.outln("") - Sys.outln(" Registration Failed: Invalid data provided!") + Sys.println("") + Sys.println(" Registration Failed: Invalid data provided!") } } // Calculator with user input + VALIDATION SHOWCASE local interactiveCalculator() { - Sys.outln("=== Interactive Calculator ===") + Sys.println("=== Interactive Calculator ===") - Sys.outln("Enter first number:") - num1 = (int) input + Sys.println("Enter first number:") + num1 := (int) input - Sys.outln("Enter second number:") - num2 = (int) input + Sys.println("Enter second number:") + num2 := (int) input - Sys.outln("Enter operation (+, -, *, /):") - op = (string) input + Sys.println("Enter operation (+, -, *, /):") + op := (text) input // NEW: Showcasing conditional chains for validation! if op == any["+", "-", "*", "/"] { - result, operation = [formula, operation]:calculate(num1, num2, op) + result, operation := [formula, operation]:calculate(num1, num2, op) - Sys.outln("") - Sys.outln("Calculation Result:") - Sys.outln(num1 + " " + op + " " + num2 + " = " + result) - Sys.outln("Operation: " + operation) + Sys.println("") + Sys.println("Calculation Result:") + Sys.println(num1 + " " + op + " " + num2 + " = " + result) + Sys.println("Operation: " + operation) } else { - Sys.outln("") - Sys.outln("Error: '" + op + "' is not a valid operation!") - Sys.outln("Please use one of: +, -, *, /") + Sys.println("") + Sys.println("Error: '" + op + "' is not a valid operation!") + Sys.println("Please use one of: +, -, *, /") } } // Loop demonstration with input share numberSeries() { - Sys.outln("=== Number Series Generator ===") + Sys.println("=== Number Series Generator ===") - Sys.outln("Enter start number:") - start = (int) input + Sys.println("Enter start number:") + start := (int) input - Sys.outln("Enter end number:") - end = (int) input + Sys.println("Enter end number:") + end := (int) input - Sys.outln("Number series from " + start + " to " + end + ":") + Sys.println("Number series from " + start + " to " + end + ":") - Sys.outln("") - Sys.outln("=== DEFAULT STEPS (No 'by' clause) ===") - Sys.outln("Counting up naturally:") + Sys.println("") + Sys.println("=== DEFAULT STEPS (No 'by' clause) ===") + Sys.println("Counting up naturally:") for i in 1 to 5 { - Sys.outln("Default step: " + i) // 1, 2, 3, 4, 5 + Sys.println("Default step: " + i) // 1, 2, 3, 4, 5 } - Sys.outln("Counting down naturally:") + Sys.println("Counting down naturally:") for i in 5 to 1 { - Sys.outln("Default step: " + i) // 5, 4, 3, 2, 1 + Sys.println("Default step: " + i) // 5, 4, 3, 2, 1 } - Sys.outln("User range - smart default:") + Sys.println("User range - smart default:") for i in start to end { - Sys.outln("Smart default: " + i) // auto +1 or -1 based on start/end + Sys.println("Smart default: " + i) // auto +1 or -1 based on start/end } - Sys.outln("") - Sys.outln("=== BASIC STEPS ===") - Sys.outln("Enter step size:") - steps = (int) input + Sys.println("") + Sys.println("=== BASIC STEPS ===") + Sys.println("Enter step size:") + steps := (int) input for i by steps in start to end { - Sys.outln("Step by " + steps + ": " + i) - } - - // Manual assignments - for i by i = i + 1 in start to end { - Sys.outln("Manual i=i+1: " + i) - } - - // Compound assignments - for i by i += 1 in start to end { - Sys.outln("Compound i+=1: " + i) + Sys.println("Step by " + steps + ": " + i) } // Operator prefixes for i by +1 in start to end { - Sys.outln("Step by +1: " + i) + Sys.println("Step by +1: " + i) } // Counting down with various methods for i by -1 in 10 to 1 { - Sys.outln("Countdown by -1: " + i) - } - - for i by i = i - 1 in 10 to 1 { - Sys.outln("Countdown manual: " + i) - } - - for i by i -= 1 in 10 to 1 { - Sys.outln("Countdown compound: " + i) + Sys.println("Countdown by -1: " + i) } - Sys.outln("") - Sys.outln("=== MULTIPLICATIVE STEPS ===") + Sys.println("=== MULTIPLICATIVE STEPS ===") // Multiplicative patterns for i by *2 in 1 to 32 { - Sys.outln("Doubling: " + i) + Sys.println("Doubling: " + i) } - for i by i = i * 2 in 1 to 32 { - Sys.outln("Doubling manual: " + i) + exponent := 1 + powerValue := 2 + for i in 1 to 6 { + Sys.println("Power compound: 2^" + exponent + " = " + powerValue) + exponent = exponent + 1 + powerValue = powerValue * 2 } - for i by i *= 2 in 1 to 32 { - Sys.outln("Doubling compound: " + i) - } - for i by *+2 in start to end { - Sys.outln("Step by *+2: " + i) + Sys.println("Step by *+2: " + i) } - Sys.outln("") - Sys.outln("=== DIVISION STEPS ===") + Sys.println("") + Sys.println("=== DIVISION STEPS ===") // Division patterns for i by /2 in 64 to 2 { - Sys.outln("Halving: " + i) - } - - for i by i = i / 2 in 64 to 2 { - Sys.outln("Halving manual: " + i) - } - - for i by i /= 2 in 64 to 2 { - Sys.outln("Halving compound: " + i) + Sys.println("Halving: " + i) } for i by /+2 in 32 to 1 { - Sys.outln("Step by /+2: " + i) + Sys.println("Step by /+2: " + i) } - Sys.outln("") - Sys.outln("=== PRACTICAL PATTERNS ===") - Sys.outln("Powers of 2:") + Sys.println("") + Sys.println("=== PRACTICAL PATTERNS ===") + Sys.println("Powers of 2:") - // Various power patterns - for power by *2 in 1 to 64 { - Sys.outln("2^" + power + " = " + power) + exponent = 1 + for value by *2 in 2 to 64 { // Start from 2 (2^1) + Sys.println("2^" + exponent + " = " + value) + exponent = exponent + 1 } - for power by power *= 2 in 1 to 64 { - Sys.outln("Power compound: " + power) - } - - Sys.outln("Countdown sequences:") + Sys.println("Countdown sequences:") // Natural countdown for count in 10 to 1 { - Sys.outln("Natural countdown: " + count) + Sys.println("Natural countdown: " + count) } // Explicit countdown for count by -1 in 10 to 1 { - Sys.outln("Explicit countdown: " + count) - } - - Sys.outln("Growing sequences:") - // Complex patterns - for grow by *2 + 1 in 1 to 50 { - Sys.outln("Growing: " + grow) + Sys.println("Explicit countdown: " + count) } - for grow - by grow = grow * 2 + 1 - in 1 - to 50 { - Sys.outln("Growing manual: " + grow) + grow := 1 + for i in 1 to 5 { // Limit iterations + Sys.println("Growing: " + grow) + grow = grow * 2 + 1 } - Sys.outln("Mixed operations:") + Sys.println("Mixed operations:") for mixed in 1 to 20 { - Sys.outln("Mixed default: " + mixed) + Sys.println("Mixed default: " + mixed) } for mixed by +2 in 1 to 20 { - Sys.outln("Mixed +2: " + mixed) + Sys.println("Mixed +2: " + mixed) } for mixed by -2 in 20 to 2 { - Sys.outln("Mixed -2: " + mixed) + Sys.println("Mixed -2: " + mixed) } } // Additional demo for edge cases share edgeCaseLoops() { - Sys.outln("=== Edge Case Loops ===") + Sys.println("=== Edge Case Loops ===") // Single element ranges - Sys.outln("Single element:") + Sys.println("Single element:") for i in 5 to 5 { - Sys.outln("Single: " + i) // Should Sys.outln: 5 + Sys.println("Single: " + i) // Should Sys.println: 5 } // Zero-step ranges - Sys.outln("Zero range up:") + Sys.println("Zero range up:") for i in 0 to 0 { - Sys.outln("Zero up: " + i) // Should Sys.outln: 0 + Sys.println("Zero up: " + i) // Should Sys.println: 0 } - Sys.outln("Zero range down:") + Sys.println("Zero range down:") for i in 0 to 0 { - Sys.outln("Zero down: " + i) // Should Sys.outln: 0 + Sys.println("Zero down: " + i) // Should Sys.println: 0 } // Negative numbers - Sys.outln("Negative ranges:") + Sys.println("Negative ranges:") for i in -5 to -1 { - Sys.outln("Negative up: " + i) // -5, -4, -3, -2, -1 + Sys.println("Negative up: " + i) // -5, -4, -3, -2, -1 } for i in -1 to -5 { - Sys.outln("Negative down: " + i) // -1, -2, -3, -4, -5 + Sys.println("Negative down: " + i) // -1, -2, -3, -4, -5 } // Large steps - Sys.outln("Large steps:") + Sys.println("Large steps:") for i by 10 in 0 to 50 { - Sys.outln("Large step: " + i ) // 0, 10, 20, 30, 40, 50 + Sys.println("Large step: " + i ) // 0, 10, 20, 30, 40, 50 } } // Main method - program entry point share main() { - Sys.outln("=== CODERIVE INTERACTIVE DEMO ===") - Sys.outln("") + output "=== CODERIVE INTERACTIVE DEMO ===" + Sys.println("") // Demonstrate arrays demonstrateArrays() - Sys.outln("") + Sys.println("") // Get user information getUserInfo() - Sys.outln("") + Sys.println("") // Calculator demo interactiveCalculator() - Sys.outln("") + Sys.println("") // Number series demo numberSeries() - Sys.outln("") + Sys.println("") // Edge cases edgeCaseLoops() - Sys.outln("") + Sys.println("") - Sys.outln("=== DEMO COMPLETE ===") - Sys.outln("Thank you for using Coderive!") + Sys.println("=== DEMO COMPLETE ===") + Sys.println("Thank you for using Coderive!") } - -} +} \ No newline at end of file diff --git a/src/main/cod/LoopTest.cod b/src/main/cod/LoopTest.cod index bb3a7782..c5288722 100644 --- a/src/main/cod/LoopTest.cod +++ b/src/main/cod/LoopTest.cod @@ -1,15 +1,12 @@ -unit sample -share LoopTest { - -share main() { -output "Enter start" -start = (int) input -output "Enter end" -end = (int) input -for i by *+2 in start to end { -output "Result is: " + i -} +use { + lang.Sys } +Sys.outln("Enter start") +start := (int) input +Sys.outln("Enter end") +end := (int) input +for i by *+2 in start to end { +Sys.outln("Result is: " + i) } \ No newline at end of file diff --git a/src/main/cod/NaturalArrayTest.cod b/src/main/cod/NaturalArrayTest.cod new file mode 100644 index 00000000..def1c67c --- /dev/null +++ b/src/main/cod/NaturalArrayTest.cod @@ -0,0 +1,115 @@ +use { lang.Sys } + +share main() { + Sys.outln("=== NUMBER TYPE PRECISION TEST ===\n") + + // Test 1: Integer type boundaries + Sys.outln("1. Testing integer type boundaries:") + + // Small (should be Integer) + int small = 42 + Sys.outln(" small = " + small + " (should be 42)") + + // Medium (should be Long) + int medium = 9223372036854775807 // Long.MAX_VALUE + Sys.outln(" medium = Long.MAX_VALUE = " + medium) + + // Check if we can add 1 without overflow + int mediumPlus1 = medium + 1 + Sys.outln(" medium + 1 = " + mediumPlus1 + " (what happens?)") + + // Huge (what does this become?) + int huge = 999999999999999999999999999999999 + Sys.outln(" huge = " + huge) + Sys.outln(" Is huge exact? " + (huge.toString().length() > 15 ? "Probably not" : "Maybe")) + + // Test 2: Floating-point precision + Sys.outln("\n2. Testing floating-point precision:") + + float a = 0.1 + float b = 0.2 + float c = a + b + Sys.outln(" 0.1 = " + a) + Sys.outln(" 0.2 = " + b) + Sys.outln(" 0.1 + 0.2 = " + c) + Sys.outln(" 0.1 + 0.2 == 0.3? " + (c == 0.3)) + Sys.outln(" Difference: " + (c - 0.3)) + + // Test 3: Large integer preservation in NaturalArray + Sys.outln("\n3. Testing NaturalArray with large numbers:") + + // Create array with huge bounds + bigArray := [1000000000000 to 1000000000005] // 1 trillion to 1 trillion + 5 + Sys.outln(" Created: " + bigArray) + + for i in 0 to 5 { + Sys.outln(" bigArray[" + i + "] = " + bigArray[i]) + } + + // Modify with large number + bigArray[2] = 888888888888888888888 + Sys.outln(" After setting bigArray[2] = 888888888888888888888:") + Sys.outln(" bigArray[2] = " + bigArray[2]) + + // Test 4: Arithmetic with huge numbers + Sys.outln("\n4. Testing arithmetic operations:") + + int x = 100000000000000000000 + int y = 200000000000000000000 + int sum = x + y + int product = x * 3 + + Sys.outln(" x = " + x) + Sys.outln(" y = " + y) + Sys.outln(" x + y = " + sum + " (should be 300000000000000000000)") + Sys.outln(" x * 3 = " + product + " (should be 300000000000000000000)") + + // Test 5: Division and fractions + Sys.outln("\n5. Testing division:") + + float div1 = 1.0 / 3.0 + float div2 = 1 / 3 + Sys.outln(" 1.0 / 3.0 = " + div1) + Sys.outln(" 1 / 3 = " + div2 + " (integer division?)") + + // Test 6: Type inference + Sys.outln("\n6. Testing type inference:") + + inferred1 := 42 + inferred2 := 42.0 + inferred3 := 100000000000000000000 + + Sys.outln(" inferred1 := 42 → type? value = " + inferred1) + Sys.outln(" inferred2 := 42.0 → type? value = " + inferred2) + Sys.outln(" inferred3 := 100000000000000000000 → type? value = " + inferred3) + + // Test 7: Edge cases + Sys.outln("\n7. Testing edge cases:") + + // Very precise decimal + float precise = 3.14159265358979323846264338327950288419716939937510 + Sys.outln(" π to 50 digits = " + precise) + Sys.outln(" Actual stored length: " + precise.toString().length() + " chars") + + // Scientific notation + float scientific = 6.02214076e23 + Sys.outln(" Avogadro's number = " + scientific) + + Sys.outln("\n=== ANALYSIS ===") + Sys.outln("Based on these tests:") + Sys.outln("1. If huge integers preserve all digits → You have BigInteger!") + Sys.outln("2. If 0.1 + 0.2 == 0.3 exactly → You have exact decimals!") + Sys.outln("3. If NaturalArray works with huge bounds → Formula computation works!") + + Sys.outln("\nCurrent findings from your code:") + Sys.outln("• Your 'int' handles: Integer (32-bit), Long (64-bit), Double (lossy for huge)") + Sys.outln("• Your 'float' is Java's double (64-bit IEEE 754)") + Sys.outln("• NaturalArray uses double for calculations") + + Sys.outln("\nRecommendations:") + Sys.outln("1. To name them 'exact'/'prec': Implement BigInteger/BigDecimal") + Sys.outln("2. Keep 'int'/'float': Be honest about limitations") + Sys.outln("3. NaturalArray is already revolutionary regardless!") + + Sys.outln("\nRun this test to see the truth! 🔍") +} \ No newline at end of file diff --git a/src/main/cod/ParamSkipDemo.cod b/src/main/cod/ParamSkipDemo.cod new file mode 100644 index 00000000..59905065 --- /dev/null +++ b/src/main/cod/ParamSkipDemo.cod @@ -0,0 +1,131 @@ +unit paramskipping + +use { + lang.Sys +} + +share ParameterSkippingDemo { + + // Method with defaults + local calculate(a := 1, b: int = 2, c: int = 3) :: sum: int, product: int { + ~> sum: a + b + c, product: a * b * c + } + + // Another method - just returns the message + local createMessage(name: text, greeting: text = "Hello") :: message: text { + fullMessage := greeting + " " + name + ~> message: fullMessage + } + + // Method with required first param + local multiply(x: int, y: int = 5) :: result: int { + ~> result: x * y + } + + // Simple greeting method + local sayHello(name: text, volume: text = "normal") :: greeting: text { + greeting := "Hello " + name + ~> greeting: greeting + } + + // Math method with FIRST param having default too + local mathOp(x: int = 10, y: int = 5, operation: text = "add") :: result: int, op: text { + // Simple implementation without if (for now) + result := x + y // Just use add for now + ~> result: result, op: operation + } + + share main() { + output "=== PARAMETER SKIPPING TEST ===" + Sys.println("") + + // Test 1: Skip middle parameter + sum1, prod1 := [sum, product]:calculate(10, _, 30) + Sys.println("Test 1: calculate(10, _, 30)") + Sys.println(" Expected: sum=42 (10+2+30), product=600 (10*2*30)") + Sys.println(" Got: sum=" + sum1 + ", product=" + prod1) + Sys.println("") + + // Test 2: Skip last parameter + sum2, prod2 := [sum, product]:calculate(5, 6, _) + Sys.println("Test 2: calculate(5, 6, _)") + Sys.println(" Expected: sum=14 (5+6+3), product=90 (5*6*3)") + Sys.println(" Got: sum=" + sum2 + ", product=" + prod2) + Sys.println("") + + // Test 3: Skip first parameter (has default) + sum3, prod3 := [sum, product]:calculate(_, 4, 5) + Sys.println("Test 3: calculate(_, 4, 5)") + Sys.println(" Expected: sum=10 (1+4+5), product=20 (1*4*5)") + Sys.println(" Got: sum=" + sum3 + ", product=" + prod3) + Sys.println("") + + // Test 4: Message with default greeting + msg1 := createMessage("Alice", _) + Sys.println("Test 4: createMessage(\"Alice\", _)") + Sys.println(" Expected: \"Hello Alice\"") + Sys.println(" Got: \"" + msg1 + "\"") + Sys.println("") + + // Test 5: Message with custom greeting + msg2 := createMessage("Bob", "Hi") + Sys.println("Test 5: createMessage(\"Bob\", \"Hi\")") + Sys.println(" Expected: \"Hi Bob\"") + Sys.println(" Got: \"" + msg2 + "\"") + Sys.println("") + + // Test 6: Valid skip with default + result := multiply(10, _) + Sys.println("Test 6: multiply(10, _)") + Sys.println(" Expected: 50 (10*5)") + Sys.println(" Got: " + result) + Sys.println("") + + // Test 7: Multiply with explicit value + result2 := multiply(10, 3) + Sys.println("Test 7: multiply(10, 3)") + Sys.println(" Expected: 30 (10*3)") + Sys.println(" Got: " + result2) + Sys.println("") + + // Test 8: Greeting skip + greeting := sayHello("Charlie", _) + Sys.println("Test 8: sayHello(\"Charlie\", _)") + Sys.println(" Expected: \"Hello Charlie\"") + Sys.println(" Got: \"" + greeting + "\"") + Sys.println("") + + // Test 9: Math operation - skip middle (now x has default 10) + mathResult1, op1 := [result, op]:mathOp(5, _, "multiply") + Sys.println("Test 9: mathOp(5, _, \"multiply\")") + Sys.println(" Expected: result=10 (5+5), op=\"multiply\"") + Sys.println(" Got: result=" + mathResult1 + ", op=" + op1) + Sys.println("") + + // Test 10: Math operation - skip operation + mathResult2, op2 := [result, op]:mathOp(20, 5, _) + Sys.println("Test 10: mathOp(20, 5, _)") + Sys.println(" Expected: result=25 (20+5), op=\"add\"") + Sys.println(" Got: result=" + mathResult2 + ", op=" + op2) + Sys.println("") + + // Test 11: All defaults + sum4, prod4 := [sum, product]:calculate(_, _, _) + Sys.println("Test 11: calculate(_, _, _)") + Sys.println(" Expected: sum=6 (1+2+3), product=6 (1*2*3)") + Sys.println(" Got: sum=" + sum4 + ", product=" + prod4) + Sys.println("") + + // Test 12: Skip first (now has default), provide others + mathResult3, op3 := [result, op]:mathOp(_, 8, "subtract") + Sys.println("Test 12: mathOp(_, 8, \"subtract\")") + Sys.println(" Expected: result=18 (10+8), op=\"subtract\"") + Sys.println(" Got: result=" + mathResult3 + ", op=" + op3) + Sys.println("") + + output "=== ALL TESTS COMPLETE ===" + Sys.println("") + Sys.println("Summary: Parameter skipping with '_' works perfectly!") + Sys.println("Note: Single slot returns show as maps {key=value}") + } +} \ No newline at end of file diff --git a/src/main/cod/PrimitiveTest.cod b/src/main/cod/PrimitiveTest.cod index d37839de..71d324a9 100644 --- a/src/main/cod/PrimitiveTest.cod +++ b/src/main/cod/PrimitiveTest.cod @@ -1,57 +1,61 @@ -unit sample get { - cod.Math +unit sample + +use { + lang.Sys, + lang.Math } share PrimitiveTest { // Test arithmetic operations share testArithmetic() { - int a = 15 - int b = 4 - float x = 10.5 - float y = 2.5 + a: int = 15 + b: int = 4 + x: float = 10.5 + y: float = 2.5 - output "Arithmetic Operations:" - output "15 + 4 = " + (a + b) - output "15 - 4 = " + (a - b) - output "15 * 4 = " + (a * b) - output "15 / 4 = " + (a / b) - output "10.5 + 2.5 = " + (x + y) - output "10.5 - 2.5 = " + (x - y) - output "10.5 * 2.5 = " + (x * y) - output "10.5 / 2.5 = " + (x / y) + Sys.outln("Arithmetic Operations:") + Sys.outln("15 + 4 = " + (a + b)) + Sys.outln("15 - 4 = " + (a - b)) + Sys.outln("15 * 4 = " + (a * b)) + Sys.outln("15 / 4 = " + (a / b)) + Sys.outln("10.5 + 2.5 = " + (x + y)) + Sys.outln("10.5 - 2.5 = " + (x - y)) + Sys.outln("10.5 * 2.5 = " + (x * y)) + Sys.outln("10.5 / 2.5 = " + (x / y)) } // Test comparison operations share testComparisons() { - int num1 = 10 - int num2 = 20 + num1 := 10 + num2 := 20 - output "Comparison Operations:" - output "10 == 10: " + (num1 == num1) - output "10 == 20: " + (num1 == num2) - output "10 != 20: " + (num1 != num2) - output "10 < 20: " + (num1 < num2) - output "10 > 20: " + (num1 > num2) - output "10 <= 20: " + (num1 <= num2) - output "10 >= 20: " + (num1 >= num2) + Sys.outln("Comparison Operations:") + Sys.outln("10 == 10: " + (num1 == num1)) + Sys.outln("10 == 20: " + (num1 == num2)) + Sys.outln("10 != 20: " + (num1 != num2)) + Sys.outln("10 < 20: " + (num1 < num2)) + Sys.outln("10 > 20: " + (num1 > num2)) + Sys.outln("10 <= 20: " + (num1 <= num2)) + Sys.outln("10 >= 20: " + (num1 >= num2)) } // Test multiple return values - ~|intResult, stringResult - share testMultiReturn(int inputInteger) ~> inputInteger * 2, "Processed: " + inputInteger + share testMultiReturn(inputInteger: int) + :: intResult: int, stringResult: text + ~> inputInteger * 2, "Processed: " + inputInteger share main() { - output "=== COMPREHENSIVE TESTS ===" - output "" + Sys.outln("=== COMPREHENSIVE TESTS ===") + Sys.outln("") testArithmetic() - output "" + Sys.outln("") testComparisons() - output "" + Sys.outln("") - output "Multiple Return Test:" - output [stringResult, intResult]:testMultiReturn(25) + Sys.outln("Multiple Return Test:") + Sys.outln([stringResult, intResult]:testMultiReturn(25)) } } \ No newline at end of file diff --git a/src/main/cod/RecursiveForPrint.cod b/src/main/cod/RecursiveForPrint.cod index 4c27fac1..d60a76d3 100644 --- a/src/main/cod/RecursiveForPrint.cod +++ b/src/main/cod/RecursiveForPrint.cod @@ -1,19 +1,15 @@ -unit sample get { - cod.Math +use { + lang. Sys, + lang.Math } -share RecursiveForPrint { - share main() { - output "This is a test for for-loop" +Sys.outln("This is a test for for-loop") - output "Counting up:" - for i by 1 in 1 to 10 { - output i - } - - output "Counting down:" - for i by -1 in 10 to 1 { - output i - } - } +Sys.outln("Counting up: ") +for i by 1 in 1 to 10 { + Sys.outln(i) +} +Sys.outln("Counting down: ") +for i by -1 in 10 to 1 { + Sys.outln(i) } \ No newline at end of file diff --git a/src/main/cod/SlotTest.cod b/src/main/cod/SlotTest.cod index 1a3ee0c4..e73bc052 100644 --- a/src/main/cod/SlotTest.cod +++ b/src/main/cod/SlotTest.cod @@ -1,15 +1,19 @@ -unit sample get { -cod.Math + +use { + lang.Sys } -share SlotTest { +share compute(a: int, b: int) +:: sum: int, diff: int +~> sum: a + b, diff: a - b -~| sum, diff -share compute(int a, int b) ~> a + b, a - b +share trying(a: int, b: int) +:: int, int|float +~> a * b, a / b share main() { -output [sum]:compute(2, 1) -output [diff]:compute(2, 1) -} - +Sys.outln([sum]:compute(2, 1)) +Sys.outln([diff]:compute(2, 1)) +Sys.outln([0]:trying(2, 1)) +Sys.outln([1]:trying(2, 4)) } \ No newline at end of file From 57c562dd6995c5b84b4ba1ee6734d91052d91e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:53:52 +0800 Subject: [PATCH 49/54] Create Sys.cod --- src/main/cod/lang/Sys.cod | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/cod/lang/Sys.cod diff --git a/src/main/cod/lang/Sys.cod b/src/main/cod/lang/Sys.cod new file mode 100644 index 00000000..fe088ca0 --- /dev/null +++ b/src/main/cod/lang/Sys.cod @@ -0,0 +1,15 @@ +unit lang + +share Sys { + +/* auto in-between spacing between each + and +any other concats. 'printp' means print pretty. +*/ +builtin printp(inp: text) {} + +/* 'println' meaning print line */ +share println(inp: text) { +output inp + "\n" +} + +} From 3970570365458bd73a090c942b5244096ec83462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:54:13 +0800 Subject: [PATCH 50/54] Add files via upload --- src/main/cod/lang/Math.cod | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/main/cod/lang/Math.cod diff --git a/src/main/cod/lang/Math.cod b/src/main/cod/lang/Math.cod new file mode 100644 index 00000000..bf759b82 --- /dev/null +++ b/src/main/cod/lang/Math.cod @@ -0,0 +1,51 @@ +unit lang + +share Math { + + share sqrt(x: int|float) :: int|float { + if x < 0 { + ~> 0 + } elif x == 0 { + ~> 0 + } else { + // Simple square root approximation + guess: int|float = x / 2 + for i in 1 to 10 { + guess = (guess + x / guess) / 2 + } + ~> guess + } + } + + share pow(base: int|float, exponent: int|float) :: int|float { + temp: int|float = 1 + for i in 1 to exponent { + temp = temp * base + } + ~> temp + } + + share max(a: int|float, b: int|float) :: int|float { + if a > b { + ~> a + } else { + ~> b + } + } + + share min(a: float, b: float) :: float { + if a < b { + ~> a + } else { + ~> b + } + } + + share abs(x: float) :: float { + if x < 0 { + ~> -x + } else { + ~> x + } + } +} \ No newline at end of file From abf0e1aa165cc96d8e0c32d46a0c33cc7cb4b99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:56:00 +0800 Subject: [PATCH 51/54] Update quick-test.yml --- .github/workflows/quick-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quick-test.yml b/.github/workflows/quick-test.yml index edc31e64..0479a5d1 100644 --- a/.github/workflows/quick-test.yml +++ b/.github/workflows/quick-test.yml @@ -15,8 +15,8 @@ jobs: find src/main/java -name "*.java" > sources.txt mkdir -p target/classes javac -d target/classes @sources.txt - # Test with first .cdrv file found - TEST_FILE=$(find src/main/cdrv -name "*.cdrv" -type f | head -1) + # Test with first .cod file found + TEST_FILE=$(find src/main/cod -name "*.cod" -type f | head -1) if [ -n "$TEST_FILE" ]; then - java -cp target/classes cdrv.runner.CompilerRunner --bytecode "$TEST_FILE" - fi \ No newline at end of file + java -cp target/classes cod.runner.CompilerRunner --bytecode "$TEST_FILE" + fi From 48f43a13d1f51dbf2ce9ef695db44090d6153d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 13:57:26 +0800 Subject: [PATCH 52/54] Delete lib directory --- lib/.nodata | 1 - lib/antlr4-runtime-4.13.2.jar | Bin 326307 -> 0 bytes 2 files changed, 1 deletion(-) delete mode 100644 lib/.nodata delete mode 100644 lib/antlr4-runtime-4.13.2.jar diff --git a/lib/.nodata b/lib/.nodata deleted file mode 100644 index 8b137891..00000000 --- a/lib/.nodata +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/antlr4-runtime-4.13.2.jar b/lib/antlr4-runtime-4.13.2.jar deleted file mode 100644 index 350c1d0f47d4e0807214093cc1c54f1edbe8925a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 326307 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\dL}4Vf^iQ5G z)7dH4nEr(Ehz+aG{+)gQkZX|y_xUYIBuD&c!mCirS@m`ETYG=m7G~(ysUCzkPcl*rhXS|JpygA8$7Z9q&{c!QuIx)chkntbd<#WgRpm`qa-Cq%N z>g9Oh{Ll#r80qDFaf`qB2=5Qr6*Ncl7u#ez<@eqx@OY66`63ISw&#%&i7Qm}^kTwX zGe&vH7rzTATtPl-oY!LW2kh5=_=S8?oaeHURN;N3uU^<$eNHPdPtC*!YgYJhLF0ZP zDUA!h8bE#lp0Pg=za-)ZwEWg~Jzn`k;JlLiZyrkK)TL_!f8}S9p><199aJGw65xFV zT^@)EL@^-728%!q_!b^YNqp)pr~9~vaAm&P*|}qvyrh?CYC@_ z86wjOlk2fNoS+X^77QwrY|p<^e-Fz*pwOd zh%sCtvBmIWC@651lVL8ZUiVJ3B8qo4#)A4{ZM_++@zs2Ti5I?0?f*3+$Mrkmtit_sN`jAXb$9BH9K&Y4h6 zbYF?RbEL}gFHLepelGpgO?+W0rNj=(phTQ)p_{uLsY!CKLThSY-zVEZX9hGl1v@`b_S{BsOl4ykUH^xzc;YaH7>;7)6+OC61aFow8$?A zpN4UL-S9;b+@(oNr%xbc?>tglV`TlMEIQfl%*{))2n>H+j!W#0T(HmpJTB0S+|74NK>exK{scEoeEY z4KcM?<8~#5LL;Lo-B5)Ob{Tgus&?bK1f!One7e?NQ4}r*-bHC{kL11uj~qc&ESEWMT^^9Pvlpd>!$XfHE~Qc!cSw7A@P#%$by z{8zElbORl_*)kbs%DYMaPJWZ8N&3*j>F@-9KsOGK{7FR0Gt^VoNi!9iB(gA zGa;#jTU0Tb2j|iCzzIIC(8X}D*o75tu7cAercOx{fKbIa}96!J>A!W1f85r}6(EqDWd0`z`=2-=4X&pr>Pu?tFJJOy}hM;IAUwu8t zKiz35A2nD!Qu&7gX;Yg2jWByzJNabJW8v|b)|JT@Vt(2(4E~-Vpk~X}G{^i}*&J=k zp`g-I?sV5OTWq2-b{f15*NU*ZMA~}bRGTMny)vHXRP`K~0n$7VaSA~tx#h~dPJ1fS z5l;eQiXIp(+{#}ki{7y*!Z>GE?k2c=4tAPXQci`GPOD+kamr(K0|w(m zq`14N>M*(uh59UDxbe;-`A=_1i_T#+HNCqx;?vg|f8f4Dp7RvQ!(Y9?%EMo^;F9?Y zI`tAco+a4F28X!=6>@S0WeG7hA*BKj*VSpYTo>n2SqU~CB$h5Ss}DP=3t8T!d$pEa z+_#OffOICoF@ei>q{AS~@|pxrT8`Vr6UD_T{9*D2!;vC?DMk5d47s0FGxMnOrUj{0 zR@V5g{Yy(fkd8E}yaa70C+S6eJwK?8D)*%&7RcEDCpyyrSOFgOuV}!Z=lA1knm(gV zsZ%zqkW1B@)wVj#^M3K;Nyag-vI{9)1|C>BfJf<|;+8|x3nM@uElB-Se&EkNMhJqht(x#R~h zOaEN=>;Jhb=bSTj>hBMZozevdAkOdO-$xhc&wEgTNVN>4U6*KY$Zb@DU*$R$l|py5Zf! z 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
-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∓jxH#T+D*Wcs#rdH)k%%Q+?!Oek6hi`@$Z)?1d z`tp`<9r5542yNr(F|qP=bMz_jNX~r5->M&Dep!MgWFhuqa$tYQ=ZkNTTNP4F$CPBr zhje>|b%vw{YhC?LC%D;Exv^GR`FQcjY${{tNAeIk(Kv>#1`qUmZpr#S-9E-V7s}Pn z88F)UW4IIY&@g?zZ`_d_RiyHrJv$~F)(&W>mlo}V?Jo0E9t>R5C>ka?_RbnN6M-sc&vP?osS zH$?pwnl>(-&Dr_!@7FI?)F%G=&~terC`0Pxl+L@y&GG4G8bdOSZP6|d)Y1(z`v(;2 z*V?{>_UoLbPk31Oti!qD;-fRiIdf0qN_vf$k}hgs4J(Qp`M+eTNJlqO7T5Ckd$iU~ z>KW~+hc&GF`Wd>3d_ri{EVNTrME$|#!m01FqJtUd^NY2f&@Fjnzkcz2Le$GkF}`qW zcD^)Xh5F1zPsY6UgqYXe*Jp0LNi!h9%BhxU`WOjVon@|v?AbU|S7kH6I&NlWKJGI$=p;DID;97kq~L_X)awyptw zzx#Cp5&80#WYTEe<*i@6XFdtP#tqhd_GI26lPaYoyvFg9tl=*&uaL)|=%yM(ES*9e z3mnBOKTY+uo)|3|^27WN!BX{SJlKy4+ROituql%1Lg0&Vy+N$-9Gmq!G%BFfxRjrs?4+pb+a(h>d zMbk}-EyBOZ#4}x7Co=Ov(`ZeuJS)sp&Z$Dda{icQ5nXPVk&z#sCDHJWYr2YzG@^Gt zxVd`r8Yh_^QJ^B^4|G36df{F2a7*rm)-!Wv$5#1{y<-TUYFs>9G)4idR;(}|uFm!( zEMBaCO|v~-^NDe&>9M*;hGL1l;Mf&G>>nBKLk_`x??&IW()oCiP|W?{i!Z}12tC3b z^hUESc_E$xhSME*M(wGlbWO0nNU`secT-!uvzMh?-ttumMyOnuBVC4_>sI*1#ZzAJ zw6uxSY3>=_(77-c1{!t}W45v=*?f{K-0Rjyzhe+SAs{qka8HSQF*SN(p&VP!)Is(I z56^&6gL7&3g8kL}qrK2pP2$_bau0-iujdeAjKVHVAd5SE9?pgRycu!v@-4*znM1 zPL8s^=vWNw(77}?%@-j&?@PnIC0Nn3M*l(J3qdE@SC5U&Mc?q3=i7VudE3MICE8i? zPxJUNUwppKlX5FlF`t1v*09Y~c~4%S$@(8Wl}K$%=|Z7zE6lme1L% zaA}J*>%45O$owppvijI7-^fAlY;C2^q#wTt3xEI3$uok6-*E3uQt*5te6GC6!!yPk z*s`dnJ1Rl3;1}_Wo>_i&5;N)(?Z)vlS9_ms2&g?@4cdOcbyrmd-3?rCj5tG*>H3qh z15B0Cff2^}!;Ua^61ScEQxPu)E7TqVt7V9O6>(>ie3O@zkg#b!E34J`b$2k-=na32Ce)Gj zG=y9*tLIx}N?CS+vl#wF;W=#l7-JVU$^}`amhkmt)_L*{<)+TtDqNiyW-%k-p`^Wf zlr_2*cGZFI856AWLz4p;{^RXRP4d#8es0cQXi^AE{g~g=rvOp2fezxk7^EapVDU>= zxO+c;cUI_*?#Qu|H1~+Bv{Q(GWq5Fz_b#~R^p~}BBo=H_)U!YRA(waRTH5?e<6=D= zibvWa8vd;v5g&r1Ul`(FWBHC%CK-YotwlqrAH3;g(&rNuI7dT+CGT~gIqE&1U-f4S3UdF^}2WpKHAJ{-006yDsU`iR^cloKCw}u;h(-|H+nEc5o34A+_@6Etz>$Ey@_L9I6I^#uE!&{YcwY!>*yHz!u^D| z!Z!>)K-2E9Dzo3f`?>W6jmre%0)8bSc{|^GTf7qLO##0Wb;;MOXrYxMCtgUlzAm~g zAN}4|*;9q@!At8k3U!4G$8{b@6rC)XnnKi-G?7mJMxZMnz_jXx!|Dor&7~yF%flMt z3_%>3YIUe-gXIE-HiL#QPAgo(lnlWk8T0v6rEe{Dn??1}QEvJQp83w4{srci;k$lm zcjU%y(v8Yfz8ij2VXgXU|k87VwBRmwW?K>qoA+h~vt4qlOt*D3s^ze-NbdDz zjUFk&O!_s;dQ3bi!!@#EDR>^IC7&;mMLaV8m1mCq*Y^+K%f`poXV%-**sFmYuB$FmyrI@bAkQ`z4D_eFGjqN3{|*Mna|%3o_aPW`n2&q zI+-Gw2GOyVb9pk<(}dP81s$+?MrV^VKYXRGG~U(a@0<~aN>Q1`y*dSnHD)eLOc9gV zGxdJK{gt~c(2u&K2c69KpMfA;M-X*GXGB|Dp5#|7)6lpx7B!PShwM*j6|_=aNzT(f z=>zpaH$M0ET;Og}D_M1};i5jeO_DTFT;b*_XPeC*<}>g2p}lW)5D&9XC`!$wJ?Xr} zTbI?j_4#)uNk<;mA1B9n*qlsPag(3tgM?Y>BV9ghSL-8}33!Cp8Uyd$>v8XS zF?Fg{tc2-)N47@H)3O0FB8dO+`f1$OfQ#UOB+lYgy5{GfUQ*D=gqAul7F~SxA&b-B zUx_Hg#@6T37ei;kR3<}ckAz{=gFJ!pT-7`Gc=kPU9x@g&W;<9NYBd1(Xg>f{s6B9Nb0guZm-2gczRb_tnt?iWp z@6!uP`DwN@mrZ9WMa7STv#Nr*F049|I2^;LwJ3j5_}VJ7=qD$^g+-0(XS6w=9|gbr zRvLUZ2QS3cm)SpW;mXGv^5>rVGTk*NW3k#dd*jF+&NZjm4{y)RF43Jj)+`5wK6<3O z5&Y7|&*q8gmpknfE~7uGnxlIHa&s=#z8v_{Z{of9=7=h`y+CPo%TJ%^0;isF%NU;! z|Bs(+Zhvmc^Vy*I)j4BKK$Lwxpv)^be)?*$HjzEMDy!u7t*l-`(zjE_uWx#kemPpg z99Q3dyp(py06&s;Z2st1oFtzy;&A%FD9e_xL)2hfs|AmW(N3$MSh2+F=4``wkC^AyTg>FFEnfo4kH&vkgrfDzPC|;q=m? zAp*nn5&`T9mH3}btkf&2HlAw_RA!VshsFwHJdR}?ug|?Ws98_{%{}GF*08w~RNyWSaT$=cl6|)A zZ`Pf@rucW3K`G8Y z%C76|8C%04Js0T$9q1*G^zWv8<=xDtXU^sz)LyIM$gL7yoNy^!FWZ5J-+~~DCt`}K zxzSQoIHHJKO(2m=ATsQILp2B8ws>nvMVZBOp_7AS)x!4cjt>Su2n*gHGGJd1#sjIq z)`@I;lUD!IiWz0j5o?kA^_Toe`$=w&E*To&dx?;Ul7=m9#QWumo?O)`!nsr|cQ!-& z5gp6rmN4x*^z4%qSJap#-3oQy9eZ$jY5rIE*I^wGTMGkg=8XBq;^uQ6Zdbdmcs*cP z(&uEjXGAb7E8c(?)VsY2?vqU~6HDjaG7H#5%T|qDe3uGkPvq!2|6Vk@Bh~3?{($RN zw)$G`%1`{QBWR(iUyr5ScBJLY#=1MKDK5QX2iYLjhfFX&8NB!??YpExjDo3uBcW!h zwU11LPcuWZNNdzX`Qgfz2e;|4)_n#T2gc@`X`Z}$SW0=%swQpX^kv$J`X_vG+*-cu zxh=P1F|Ms(AV&Di(+P=Cpdg&sXlUmS8{v19WRLr{2M4Q?_`;%GquR7=l%M)b&EnB3 zD(fYa&c{n(Wu>PGo`|ND7!va63~Ym0d23Ire_>sp)JyEBY7V(+vL%1^=Fg#dJdHEN z4gGQDQ%TE1E=ev6B0s|4`feSsWP%M&2gg@Ay>|E%5Q@n&P;#q@OX*?rlMupI=l<$o zvJ1`C^{!<64+XI&@hyj|8^|u4Xq^6*ggY}xt#pwKccuNB|FbD9=elO&Qf6b5qpHQ} zjJ($ET(K}5Ci3c|RSle1l3&dCytq5#-2Kcl`DBjbc5H}v{)isS_p)Mk$BdJ5s(MEU z!iTaI&)HxP*s|-%E0q!orC#xPdu8(SIg6b27is9{T`uNu80P)Zn?9D>9lJ89)pbE{ zj_9g^T>J|)XnMg^diMDd<6}N1*-&2mX^ym;!Y|ceGaNQv{wtX>OSkojDdsWH9l_~B zw<>3lCkw)y?cPRjyITys8{u90`gPvcNs|i!iSryi;>NU@&{B5?MObYTmrC1vRBxU99*kCtK?wl!>iRkl`g;7pNE}qS)qvRA{XIklB zf1U82R1w$XvLRKZkwce$NomAieCLUQylAg~_5*v4H@OSzp$b^&i>M-54~)eB;}S&-Cb5nq)qmG2m`1xZ)La>vgQQkx_v9 zukskDFVL^0=0?k-URAMoDGct*NC{ENbCjs3xMDjjFV0QPD(9r*v47W~t;NZa9?Eun zJSt&G>y4>N`-}3tM1At9-ikhfTO=Mr!{gW?3ss9`OBcBkYuQElBXLZJ2*(7rU3r7n zzoyOqGH0srx;5U}$Ez^^L@)W8FL`VwK}FhqGS7fk*Rzi|X;ukf<5B9S>d%&LSz@_= zIu`9G^-j8PlV-3A9546vOo^3KeQ3r@?BciE8=uw)@e@O|*-zKFQ9!jgNAX$C1hBK@ zSL1qllAkEFPq?R@U{S68kkRIrmVdsml1^u;)5BGt*EQO6RJS|{t>P^GFHdQ>ggs&q ze0Kj@&=D}jGGXVcg@-z{URr7A$pG>(ztW zS(uwSTOjfBA7Nc*D9&FgPj7ogD%!V3hjr9ma@_Lvy;!BL8<{s)-0+LUc=ImboK?xu z?tA);Oj?Qx{SNkM3en>(+!8a6%c*M{i|b($bb}JUzFP#Q7~F(<%_TEW18hm7oj%qa zr(4!vb|Q8oEEXTKWOGZ6Eo#xQ7Vx0FYY1hacoFg8Gek(7$TFCYt@*2*S-(c>LM&HYQ8lV`rcxoIptXP35HF_#`)9N^Hs-eGa?_xTWHh0p*zNy#Lh=D zP(;~$we?axx8?cpko5I}vUYMN2`orM37>*&On3H)i87v%@ls#5YO!emsXy1BQ z5k4EtSg|m1iKkqO%3tY-%P3OjUV9_JpXbT*@#pt0i)+(lPu{dK34VExJ36Lz!)*wn z|Ep^voo|yZl5uvDTzm-c{l%yhmsoxa&okQV4r_JwGQxFk5_1NOZg1xoOcZDG&S08u z;M;Cbx}tZs8P4Es=!9HNA+FZ^ytqvl-}NL^^v!+Tp>x=i(J6e%)0(sxS2Be>0;-># z%2jx(P9_|F(ng&&V-)hjF5HJhB zC;nFuSy90~S=iU= zKCY>4=}$8fRDD|Bln}>1lCYfE(%So&P6FfhSYS{t;R%U=+d`kIf&^|#&R4f82X9ZN^i!v-J#XmK2+&pK{h#O?uTu`S4^_FfVtuTv7 zXTH?vXd9#4WuO;*CFa~ceBz9NR>~pWSb=6I=~z1m3{P5-KI9`!&Qkp>gsNACGycLeJmZrWz5!J?V(m7Yv9LpvP?aPa;Jq#mG+)&Tw zpH4`d5483h#W3}^|56XKVg0O5u5^}>OocV+{Rr;48R2As9vxRDFCBUQbXTS`ZSSwO z!_<^2rYxHJ-{zRfHE_|+dIpHls7HKQ#9zig-wiI+(U-OsCHs~@|BE-YnJDv1ALZu2 z1WR&@OO9v8t??J9DFmda_9MERCTnA2T$=?pQyCM_tA{=7$PZ=URSvS z+s^1_EB=}eR}$N3<=3M5bZ_IC1KMWn#D}shi_v*MAgDmNlFq_~bQ(ei^zFh1o{+UQQzUapn6kf=K*x zj!{HmcX*j*6?tSvYRbbaSwFlLk*SfCl~|&N4_$j$ztJ0i z>zJyWzV`;W?cfHNm+{fWaq4mA+eBWoOfQTd)^OXrhdt1Yb{wnal<~gO;1?LrKg*C% z({b94aB((U#_`D)MpX%Dz&A`k;bPN^HKQKaQXI-Z5uW%KCRV<&=fpw+ua6HrK$UD1 zoH-A_5?WPON0M7nO^(;z%pC&b1vilL{Jw#7=l=rSySI=!I@t4g+S?WC+B*yi5&b%~ zjmy&)?Dm{ZY%!Nh8>{3F2F2~Jl2KvJ$XlkI@YOD z`*MOU>+9GAO8R^Z9>#a{36-1;bis7NuGvq=934qg&jyTRu!Yu3dtCVDVR5@DE}(UE zhE1QtU_75q#yc9qqUk?!JL?fUa84 zwB9pC);qsuNgXy7*Nz<9Fd@#k-R^%+|MU;@A%of{M2a#r+8rm8(#cMJM)z@W=W$IG zbNbp|%72;cZcUm-qf>@Zimv##AAw{KS?f;r+w``vFtvN-+@M_1by}*_nQy(|$6=!@ zo~=6n9{NCo)Q9ujYupO;OoF`oms|^Kz=jJdPcve@(xI3S=qnnpQZ;)Ai5}kw>%Vk! zsXVuGgum;=hpNTdY4K2!$Pa1yy6dFuhF3fDoJwKtnWs+Q3t$|?tx(%M^&=^KM6(h?b`O%G-y6;7u(maF94aC5%e^33 zm5GF5##e=NM*g_G#5xyw#P|Sdc1=+*#B8bhR+-UJ-#0Ly+2zT5&PIASRcXqWV>q7_ zT~km@xWIj9xVVQ!qClncXc22>1Rrrzx!sFs9kUS1x?g>y$CHjvlYe-!JVyOtEPwqr z{fSxf<=jdq29ad`EgAWh2iw{P47jsmTCsO1C~4LhY`WL)LXYK<2wU3+(`6s&*S=%I zCLregJivn{_p_pz#a)esHi*t>-MLl9e&3DE5kC93`CDt*Z;E3!JmOvHow#NTi?(cj zq!brfLV02qVU*h#VwMdmBIzwsn|HOJsu-cY8&UXCXxU`DWIp z_!tM7wxmwIU>}^vu1mwOtnR*aEV4Q8KwIF$dhdzyZG#AkkgMqIVOQF#1^AoWPf$pR z!QR}kVa)fF^d2J(8&&^#tvj8!_@mE-H;+B@<2n58rlr!p~=C`#Nd(MY{1z+fXwbob=8Qvo}9?WEE0V z&x&-kg$s#&8Z|*2-&qBIGlZYXE(Tusy%~Sw!yKI*93jrGP>72%7e|wdvI@_lN}g&f zXA}F`4sMP%&Zbt?2_@cUUT!qpDe|;g|Fn{3t$TO*mzV8SSMWo>hm?Ssha>1D7$j(D z$Bv=N#9$bVfAU%&0NKU}s1<^L{qv;y!~gulo2sOmqMWR@4v(tbZvM_tV`_g9?Ij7Xb|}9zrlg*!RwCGglZ&P7q<_kil43nxTZDLg2;+ z8H_#D#r!XD3X$RLT)v7*It&Q>%%jBF-ARiI?=%7)H&C*DrM<(~?|K_5G(rS4TY&aQ zwSOlcs6IyQv4{Wr@xPf1Di}5d9^RpX*^>bMM*Y|9o4wp>RKPIR0Z19XJ8$<%^(O_x zj(z1Msivc%wab>Lae-gFPz*9jZxs|Ap&64 zLCZOISq8tU{wIMmLJlnlwF76qJ44Lu_s7*{)3Kib2;C=sZ&BNYPW6uhjs`idBFxdv z6%}xlw^wR5V3-iJoNE_#hv6z>B*0Q;P`e!|qZY-@rFTTV02#RPJ;)_wNReG2hv+|( z9u9tOAP6aDG&CLrp8J6s?<))`H%m(}wP>+Zg+wI}xnB0G&jIE%6v1_P0M ze@q7ph=v0c=K5O}yBk^eBCplC2Mpt*p?Lu33tvpU`=t6OgR%ahkfq!}wP<(E=3e|l z^I!eiKrOO?g}?_$yHBcryZj;Xb-Wz^xffwCcn7aM{}0i-`u`WA{AUkAw3zy}%uhhH3=oz3(@wZ4q#FNUhzcKqX2a;Q zAMknRM?fbKy#>1Y;c4!#7g`ObQL>;diol~Gnl`ZwQfzyB2iT4u+8=Z7JCzSEkP!qp zcEsqE;BqjgoSC_+gENxomyKMVK8xn=rtBS4u(eM_XJ-dz#05fot@`%)7Sl%{8kqu~5y5HvkbuiTEX~~PTn`bZwBI#J{sii= z3Dg78-(f}}1BaSf!5my%q2`BR-biO4tqpXiI*0)L2r94k2noI%2(SUBO@@F7{BW1uC)MBXF%kkhS%E6l#U6gk;Q{b#8~*p< zccnZBFVikI_)P^x0i^IKQ;ritqPK$q8ZOX8M21g4MUDt@c65e-yDZ_WK)@|4uHb;0 z{q2X~WVpf>=uB&1kf#wCUQI;;|DP=ed!<_`xe&JkR}Y|n@UsDSpHzRoLR4sqfWv<{ z-k;4_3i7m9Kms-(J%XQ0xBH~}!(O8TR&&sWnq38}rGR#$R*d|9^2R`5=^a2Ah{4dg z5*Y=ki|g+c$-&Lp97&K>jaZ$D0k-Z8#DZv!5{*c356|?*3PXPe5KB4`3nDmu3li|1 zOFNyJbezr1A*dY*9iaoE9^hOGcqv4glfOF%9BQxQpbfot00l|nXE*9jqoHZ2qoL97 zb}9Hx^{?zeNnw8_!EB2uuLHySNx&_l!>(OI33s6SP0(GYdk)e(ZonlXa@VmV`=@!o z<$R$1c@YJAr2}6?4o622K^-YFWM>CYuS57!{>&sEE&%-&_)62Zb$~Nd9C(3 zY@pl1fipsMM9m^d(P6Godx$E;)lA0B)og!BL?=C1Nd#Pf111gR`{zmZ7rlT47e(IH zJh9rm1~9k*8e;#GUPOh4GUKxGQtXCDPjvta;?bWc)n5x-8n^Fg>OlYd;j-$$f(#gpSCgpR0M!_!>SmXDlIl zm`4=sv7Vc@=c*PtZsa1d5+QoZ8nF{L>A;>A)L!h=yrf&%d}# zfQEL1Y44aM{_!En?9ad4-OHX<1jDepazzK0LKpnLb|r&ywrEbt4L~>sh>qZ z!?Wi_@^Jh?Yx5?DF_*cH?@_UE?w#`8W>AmeX3F8}d0e=0FxhzWDq8B6TXdp5+rrxft+58?*m_ylts6&-VUz&{9F zuIiRTGH3ud5DcP%;G(0WXoUS$sFfRVUWzbFhyB@h)pTSw0xWNUilg8k;lM-P3I-}< zXJ<37-?D-84;&ZrqD+&ufP@f`%mZLKh=anXIH*XtI@lj1mkdo!6C5CykKjcturcAI zfR-|IftpL%Ihfn-+~EuUhfE`Du)YPu2L=&<0AeQKd;A~*C}3p-U?j)?;Ty3(-+<)~ zNR@JjWm%X73S^^)-7O1%;b?%4=%z@B4njUi7}a+SwdMe>GU!M|X{((;f&FK0;@{px z5*=vb?XSRNXgAOnL}k23jFP~P_Gv?Q4AdQ^zJH0mT-yLhkOE6W3_urw=RqoY8HhR5 z1ztx03;Dn`-N>w|enBN|5+K|DkGs7@eh75rz_JjBH%9^6q2NVSm|N6`07juOx@Jem zwSc@QL8l_h{KF{}$g=j1u7`C16CN`D@BynSAb}`zFFI5t99^Jx2m3|{IbPTmAQm@3 zfepcf&CsJlhtEAA7x-h^oTjf}b|)On?jY7J!a!4y>WPX9A2_DZ&I^=<_V>4&MR~u> zfWMswIUJ%htOLad7JGio*5OX)A`A}pD!5UofHlS}2{cg7Y;qZ~CF#hPAL;k?4(1B4I;-pEH z;X&A7Yz~7#>?Bc$M!Zf8-4ej}1MwhsXoSgu@NO<3Ort^(aWV`3iRyM|MYB#&B55t zD6u84#h5Mu>@|Rm*t2i#55m@Pa6E|ht_rJgxZ=Yse zMbqJW5Wco8)De}~DXyzqy8_;^0q=-iisg9_Hr$j@VRIe1-VgVblmH)5>~-F#upJz1 z&8#7276)VjLHEiz2myQ#co7F(nLeoD9Z@HD*-alWT?X=w0f7{8jDg{Y0$9z#6;v1g z&A#^ckRDI8>+J!@@XSbd*Gj=}s{adr6yWO4V7U*(;!kXX*D-eHR1ZpT9smY(P5@bw3{r ze~@?b?#hsZ%(*u;$LkZ|o*eiJMEoQD2jc%{Opk1K6IUdlK;je{+P2hQ>6{(>8~pus z6x(v10z_9dD6n3{QOVmMe}gV`0R?CQVsgjC z`4<$_wf2X%dZ_6R)>@#Q2J%N7&m80b8~B~MUSyL=HvWWSg1~V{fU2z2u3rGZss8uC zSnANd07Bi~ptpacEPtu9o(1&a3(^p0%TJ5^9lhV7Z+|Mwg`bvKfXbo~?6u?P=MPV1 ze{3o8ga}j6C2Rm6(b%Y@QDPsM7t5k^2R8xP5Q4ryEUVOlW2}((1#oS45LXA-A*ap2>xjsksW*4*VFKmE1Kkx3Ltg&wF5;&5$1 z0~Pq62_a-DQX&fkdJ1UH2=GRTlLyAyhXUST)!!(ny{`d+fbai6?8!>awrC!}s#Z$VnoTgB0c$>^dL=!xMW~D3BYWM%-TjorV+X~4Utn_pGJFn+32y8E+WY=A zd|CpZR{>S)1?d>;E&=eH>W^iA2pao?7Lwk31?F9MW=;`x0?!2n=*~bL^xQ#miTLV# zgA>3z1HC|;L{)J^0>85{b9cqYVN>E$Q5cRqK=w?acM<8lb4N)BJ{@^h=AR`YOrQp# z2$rECpS>m;pH7Gb6Yfuey(4Cnm#!V2&i-9tr?wE?2-;8%W)BdxlRq34wv2-tSm>h+ z@j{x!59YK#?E#u%0D1y3M94;=LO!hY@t$^4fO$4FabWp~gD%@>RQPgs5Kk!J9WH*r zJkw6B*k3p~>Q3s;glK5V40|1UN9jstHfQA%HFzIT`yY znJYl<1!9mz5X1SRgOLB(wg6vus|5<3JIgx%Y-T{d8rOP%`_@pRj}a-iqvt5sRb0h1E}JFV?=H}=TM_M+q*f#-OB#ls&Q*Zi2_ZB zJ1xXe8V;5a?VGCXge6cAS97yNq7u)J8(G5hpE1BN;#i1a2^FaNRU3%8>tTIuKjEU_ z5b(3BU{rw^fvi?gQu$qON4faXV(?>#E#Uqm5I1557ru@PTf+>BWY$_zPWJdqAZSN` ziWry0w@@QGyFjGPK-JX_tR;i5pFq8BY5Icdk4)gQR=|sxF-vcwq_bNU-Cs{`398gT z0Ib8ef+FgPAQ~nLJ<)-uGt|)zNllXFeBd2# z;NZfk_O4}~#zuvC$rWmcWK9k4lEq1UplEEsQy{8yItda;u-F>HyPLZ0%qr-Bf6)aC zV31CKo4}}g1Aq|VorlVj(;bXPP=-Pc3yNdFJ` z{&Jbpd866~MC}fs5u*zy!=YeN@0H{FyaZ7NF0kZ(f|nNKq2M)sp9F+tEAq0K=^J9e z`79uTII*(8d?!z#4d^T2w1fmcE7!Xa>!4RVhEi;UbhrH_0Y=>j|(10_KWU{;_?i2@y|BnU*g z9~}c_$60ALc)H#JD2g4{hENZQ&Bh9rY02+!?N0Jb*= z(rLsp#Ddgep#OLeRrn_F{dI#xyX%|_=s`OWZV=ALS)tf|^hNSLOC%6&CD0{A zPe2Zip*mQ+03C%TY?g$2tbxwE3EF@d=ziEA3LP93fC9et9a+J3z&t)MHpGg@1;<0d z1NDQUmQOc%(P{-~!E4Y0L^p99m>+Wa{O62)WOdcWT60kkV7`%HQkN4!v&q~J3BAA8 z?7dWU7dzFz$N!MP2uJg{sk?R9kcfeh<|C&#~zZ#j;lCSgZ5q}@Gmhra0cC> zEMtcl$` From f1f8a82763a26d40d9327975f58cadfcc353f862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 14:23:56 +0800 Subject: [PATCH 53/54] Update CHANGELOG.md --- CHANGELOG.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd06343..b549acc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ All notable changes to Coderive are documented in this file. +## [v0.3.0] - The Design Leap - December 15, 2025 + +### 🚨 Breaking Changes +- **Completely abandoned `~|` to instead use `::` return slot operator** - Embracing suffix-style design, fully abandoning the prefix-style. +- **Replaced stack-based multi-arch compiler** - Ensuring lesser bug to show. (Status: Ongoing, Currently not priority) +- **Almost all classes renamed updated, and repackaged** - Full refactoring of classes and their packages for more cleaner view. +- **Replaced `` to use `` instead for variable declaration.** - `name: type` for declaration, `name: type = value` for explicit declaration and assignment, `name := value` for inferred declaration and assignment,`name = value` for reassignment + +### ✨ Major Features +- **Three World System** + - Added three distinct types of programs for Coderive: Script, Method-only, and Module. +- **From String to Text** + - Replaced the previous `string` keyword with `text`. +- **Natural Array** + - Added supports for range for arrays + - Lazy array generation + - Immutable by default but can be mutable (Note: "Use moderately") + - Supports text as natural array. +- **Added numeric shorthands** + - Added support for common numeric shorthands: K, M, B, T, Q, Qi, e + - Case for this feature will be case-sensitive. +- **Added parameter skipping and named arguments support** + +> Check for other nee minor features if you have free time... + ## [v0.2.3] - The Great Logic Revolution - November 23, 2025 ### 🚨 Breaking Changes @@ -99,4 +124,4 @@ user == any[admin, moderator, owner] ### 🎉 Initial Launch - Created first repository for Coderive programming language - Initial commit with foundational codebase structure -- Project inception marking the start of Coderive language development \ No newline at end of file +- Project inception marking the start of Coderive language development From 140039f4fce8e1074015265e9f81a85d954fe47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danison=20Nu=C3=B1ez?= Date: Mon, 15 Dec 2025 14:24:22 +0800 Subject: [PATCH 54/54] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b549acc5..d615e7ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ All notable changes to Coderive are documented in this file. - Case for this feature will be case-sensitive. - **Added parameter skipping and named arguments support** -> Check for other nee minor features if you have free time... +> Check for other new minor features if you have free time... ## [v0.2.3] - The Great Logic Revolution - November 23, 2025