From 2d448a7b0ba6d8296b723c7ce4b920404c946f89 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:39:16 +0200 Subject: [PATCH 1/8] piccodescript: Add classes for creating new modules and the return statement --- .../piccode/ast/ImportModuleCreateAst.java | 218 ++++++++++++++++++ src/main/java/org/piccode/ast/ReturnAst.java | 83 +++++++ .../piccode/rt/PiccodeReturnException.java | 26 +++ 3 files changed, 327 insertions(+) create mode 100644 src/main/java/org/piccode/ast/ImportModuleCreateAst.java create mode 100644 src/main/java/org/piccode/ast/ReturnAst.java create mode 100644 src/main/java/org/piccode/rt/PiccodeReturnException.java diff --git a/src/main/java/org/piccode/ast/ImportModuleCreateAst.java b/src/main/java/org/piccode/ast/ImportModuleCreateAst.java new file mode 100644 index 0000000..9cf0269 --- /dev/null +++ b/src/main/java/org/piccode/ast/ImportModuleCreateAst.java @@ -0,0 +1,218 @@ +package org.piccode.ast; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.piccode.antlr4.PiccodeScriptLexer; +import org.piccode.antlr4.PiccodeScriptParser; +import org.piccode.backend.Compiler; +import org.piccode.piccodescript.TargetEnvironment; +import org.piccode.rt.Context; +import org.piccode.rt.PiccodeBoolean; +import org.piccode.rt.PiccodeException; +import org.piccode.rt.PiccodeInfo; +import org.piccode.rt.PiccodeUnit; +import org.piccode.rt.PiccodeValue; + +/** + * + * @author hexaredecimal + */ +public class ImportAst extends Ast { + + public String path; + public List lifted; + + public ImportAst(String path) { + this.path = path; + this.lifted = new ArrayList<>(); + } + + public ImportAst(String path, List lifted) { + this.path = path; + this.lifted = lifted; + } + + @Override + public String toString() { + return "import " + path; + } + + @Override + public PiccodeValue execute(Integer frame) { + var nodes = loadModuleFromStdLib(path, frame); + + if (lifted.isEmpty()) { + nodes.forEach(node -> node.execute(frame)); + return new PiccodeUnit(); + } + + for (var liftedNode : lifted) { + executeLifted(nodes, liftedNode, frame); + } + + return new PiccodeUnit(); + } + + private void executeLifted(List moduleNodes, Ast liftedNode, Integer frame) { + if (liftedNode instanceof ImportId id) { + for (var node : moduleNodes) { + if (node instanceof ImportAst imp) { + imp.execute(frame); + } + if (node instanceof StatementList sts) { + executeLifted(sts.nodes, id, frame); + return; + } + if (node instanceof FunctionAst func && func.name.equals(id.text)) { + func.execute(frame); + return; + } + if (node instanceof ModuleAst mod && mod.name.equals(id.text)) { + mod.execute(frame); + return; + } + } + var err = new PiccodeException(file, line, column, "Symbol '" + id.text + "' not found in module: " + path); + err.frame = frame; + throw err; + } + + if (liftedNode instanceof ImportLift lift) { + for (var node : moduleNodes) { + if (node instanceof ImportAst imp) { + imp.execute(frame); + } + if (node instanceof StatementList sts) { + executeLifted(sts.nodes, lift, frame); + return; + } + if (node instanceof ModuleAst mod && mod.name.equals(lift.text)) { + // Recursively execute lifted symbols from inside the module + executeLifted(mod.nodes, lift.nodes, frame); + return; + } + if (node instanceof FunctionAst func && func.name.equals(lift.text)) { + var err = new PiccodeException(lift.file, lift.line, lift.column, + "Invalid import lift. Attempt to lift function as module"); + err.frame = frame; + PiccodeInfo note = new PiccodeException(func.file, func.line, func.column, + "Function is declared here"); + err.addNote(note); + throw err; + } + } + var err = new PiccodeException(file, line, column, + "Module '" + lift.text + "' not found in module: " + path.replaceAll("/", ".")); + err.frame = frame; + throw err; + } + } + + private void executeLifted(List moduleNodes, List nestedLifted, Integer frame) { + for (var lifted : nestedLifted) { + executeLifted(moduleNodes, lifted, frame); + } + } + + private List loadModuleFromStdLib(String module, Integer frame) { + var storage = getAppStorage(); + var paths = List.of(storage, "./"); + var nodes = new ArrayList(); + var _file = findModule(module, paths); + if (_file == null) { + var err = new PiccodeException(file, line, column, "Invalid module " + module.replaceAll("/", ".")); + err.frame = frame; + throw err; + } + + var path_ = _file.getPath(); + if (Context.isImportCached(path_)) { + return Context.getCached(path_); + } + + var files = _file.listFiles(); + + for (var fp : files) { + if (fp.getName().endsWith(".pics")) { + var code = readFile(fp); + if (code == null) { + var err = new PiccodeException(file, line, column, "Invalid module " + module.replaceAll("/", ".")); + err.frame = frame; + throw err; + } + var program = (StatementList) _import(fp.getAbsolutePath(), code); + var noImports = program.nodes + .stream() + .filter((value) -> { + if (value instanceof ImportAst) { + value.execute(frame); + } + return !(value instanceof ImportAst); + }) + .toList(); + nodes.addAll(noImports); + } + } + if (!Context.isImportCached(path)) { + Context.cacheImport(path, lifted); + } + return nodes; + } + + private Ast _import(String file, String code) { + Context.top.putLocal("true", new PiccodeBoolean("true")); + Context.top.putLocal("false", new PiccodeBoolean("false")); + + try { + return Compiler.program(file, code); + } catch (PiccodeException e) { + throw e; + } + } + + private String readFile(File fp) { + StringBuilder sb = new StringBuilder(); + Scanner sc; + try { + sc = new Scanner(fp); + while (sc.hasNext()) { + sb.append(sc.nextLine()).append("\n"); + } + return sb.toString(); + } catch (FileNotFoundException ex) { + return null; + } + } + + @Override + public String codeGen(TargetEnvironment target) { + return ""; + } + + private String getAppStorage() { + try { + String path = ImportAst.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath(); + return new File(path).getParentFile().getPath(); + } catch (URISyntaxException ex) { + return "./"; + } + } + + private File findModule(String module, List of) { + for (var dir : of) { + var fp = new File(dir + "/" + module); + if (fp.isDirectory()) { + return fp; + } + } + return null; + } +} diff --git a/src/main/java/org/piccode/ast/ReturnAst.java b/src/main/java/org/piccode/ast/ReturnAst.java new file mode 100644 index 0000000..4072ec9 --- /dev/null +++ b/src/main/java/org/piccode/ast/ReturnAst.java @@ -0,0 +1,83 @@ +package org.piccode.ast; + +import com.github.tomaslanger.chalk.Chalk; +import org.piccode.piccodescript.TargetEnvironment; +import org.piccode.rt.Context; +import org.piccode.rt.NativeFunction; +import org.piccode.rt.PiccodeException; +import org.piccode.rt.PiccodeSimpleNote; +import org.piccode.rt.PiccodeValue; + +/** + * + * @author hexaredecimal + */ +public class IdentifierAst extends Ast { + + public String text; + + public IdentifierAst(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + + @Override + public PiccodeValue execute(Integer frame) { + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + + + var value = ctx.getValue(text); + + if (value == null) { + var err = new PiccodeException(file, line, column, "Unknown variable `" + Chalk.on(text).red() + "` "); + err.frame = frame; + var nm = Context.top.getSimilarName(text); + if (nm != null && !nm.isEmpty()) { + var note = new PiccodeSimpleNote("Did you mean `" + Chalk.on(nm).green() + "` instead of `" + Chalk.on(text).red() + "` ?"); + err.addNote(note); + } + + var stack = ctx.getTopFrame().toMap(); + var sb = new StringBuilder(); + var entrySet = stack.entrySet(); + var size = entrySet.size(); + var index = 0; + for (var kv: entrySet) { + var key = kv.getKey(); + sb.append(key); + if (index < size - 1) { + sb.append(" ,"); + } + var str = sb.toString().length(); + if (index % 5 == 0) { + sb.append("\n"); + } + index++; + } + + var note = new PiccodeSimpleNote("Track size: " + ctx.getFramesCount()); + err.addNote(note); + + note = new PiccodeSimpleNote("Symbol table dump: " + sb.toString()); + err.addNote(note); + throw err; + } + + if (value instanceof NativeFunction nat) { + nat.frame = frame; + } + return value; + } + + @Override + public String codeGen(TargetEnvironment target) { + return text; + } + +} diff --git a/src/main/java/org/piccode/rt/PiccodeReturnException.java b/src/main/java/org/piccode/rt/PiccodeReturnException.java new file mode 100644 index 0000000..ae79f47 --- /dev/null +++ b/src/main/java/org/piccode/rt/PiccodeReturnException.java @@ -0,0 +1,26 @@ + +package org.piccode.rt; + +/** + * + * @author hexaredecimal + */ +public class PiccodeUnit implements PiccodeValue { + + @Override + public Object raw() { + return Void.TYPE; + } + + @Override + public String toString() { + return "()"; + } + + @Override + public String type() { + return "Unit"; + } + + +} From 3dfc13b1f394252806e99b548a290cd50c89f7cc Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:39:56 +0200 Subject: [PATCH 2/8] Arg: Track if the arg should export --- src/main/java/org/piccode/ast/Arg.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/piccode/ast/Arg.java b/src/main/java/org/piccode/ast/Arg.java index 211e9f4..07d9f9d 100644 --- a/src/main/java/org/piccode/ast/Arg.java +++ b/src/main/java/org/piccode/ast/Arg.java @@ -10,15 +10,18 @@ public class Arg extends Ast { public String name; public Ast def_val; + public boolean export; public Arg(String name, Ast def_val) { this.name = name; this.def_val = def_val; + this.export = false; } public Arg(String name) { this.name = name; this.def_val = null; + this.export = false; } @Override From 0921fcb4ce30228928703ba5b261067a209997d7 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:40:55 +0200 Subject: [PATCH 3/8] CCOptration: Fix symbol access. --- .../java/org/piccode/ast/CCOperationAst.java | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/piccode/ast/CCOperationAst.java b/src/main/java/org/piccode/ast/CCOperationAst.java index 416943f..9500023 100644 --- a/src/main/java/org/piccode/ast/CCOperationAst.java +++ b/src/main/java/org/piccode/ast/CCOperationAst.java @@ -1,5 +1,6 @@ package org.piccode.ast; +import com.github.tomaslanger.chalk.Chalk; import java.util.concurrent.ExecutionException; import org.piccode.piccodescript.TargetEnvironment; import org.piccode.rt.Context; @@ -34,18 +35,37 @@ public String toString() { @Override public PiccodeValue execute(Integer frame) { - if (lhs instanceof IdentifierAst id && Context.modules.containsKey(id.text)) { - var mod = Context.modules.get(id.text); - + if (lhs instanceof CCOperationAst op) { + var mod = (PiccodeModule) op.execute(frame); if (!(rhs instanceof CallAst) && !(rhs instanceof IdentifierAst)) { - throw new PiccodeException(file, line, column, "No node " + rhs + " found in module " + id.text); + throw new PiccodeException(file, line, column, "No node " + rhs + " found in module " + mod.name); } - + + var id = new IdentifierAst(mod.name); + id.file = file; + id.line = line; + id.column = column; return process(id, mod, frame); } + + if (lhs instanceof IdentifierAst id && Context.top.getValue(id.text) != null) { + var mod = Context.top.getValue(id.text); + if (!(rhs instanceof CallAst) && !(rhs instanceof IdentifierAst)) { + throw new PiccodeException(file, line, column, "No node " + rhs + " found in module " + id.text); + } + return process(id, (PiccodeModule)mod, frame); + } - var err = new PiccodeException(file, line, column, "Invalid use of `::`. Expected a module on the lhs"); + var err = new PiccodeException(file, line, column, "Invalid use of `::`. Expected a module on the lhs, but found " + Chalk.on(lhs.toString()).red()); err.frame = frame; + + if (lhs instanceof IdentifierAst id) { + var nm = Context.top.getSimilarName(id.text); + if (nm != null && !nm.isEmpty()) { + var note = new PiccodeSimpleNote("Did you mean `" + Chalk.on(nm).green() + "` instead of `" + Chalk.on(id.text).red() + "` ?"); + err.addNote(note); + } + } throw err; } @@ -75,8 +95,7 @@ private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame) return result; } if (node instanceof ModuleAst _mod && _mod.name.equals(_id.text)) { - node.execute(frame); - return Context.modules.get(_id.text); + return node.execute(frame); } } @@ -105,7 +124,7 @@ private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame) } if (node instanceof ModuleAst _mod && _mod.name.equals(_id.text)) { node.execute(frame); - return Context.modules.get(_id.text); + return ctx.getValue(_id.text); } } From d7fa4211c23003b5f99634e9182a0b6bd895515b Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:41:16 +0200 Subject: [PATCH 4/8] DotOperationAst: Fix symbol access --- .../java/org/piccode/ast/DotOperationAst.java | 70 +------------------ 1 file changed, 1 insertion(+), 69 deletions(-) diff --git a/src/main/java/org/piccode/ast/DotOperationAst.java b/src/main/java/org/piccode/ast/DotOperationAst.java index cedafa9..d3b4c6e 100644 --- a/src/main/java/org/piccode/ast/DotOperationAst.java +++ b/src/main/java/org/piccode/ast/DotOperationAst.java @@ -36,7 +36,7 @@ public String toString() { @Override public PiccodeValue execute(Integer frame) { - if (lhs instanceof IdentifierAst id && Context.modules.containsKey(id.text)) { + if (lhs instanceof IdentifierAst id && Context.top.getValue(id.text) != null && Context.top.getValue(id.text) instanceof PiccodeModule) { var err = new PiccodeException(file, line, column, "Cannot access the module `" + id.text + "` using dot. Please use `::` instead"); err.frame = frame; throw err; @@ -56,10 +56,6 @@ public PiccodeValue execute(Integer frame) { return processArrayIndexing(tupl.array(), rhs.execute(frame), frame); } - if (left instanceof PiccodeModule mod) { - return process(new IdentifierAst(mod.name), mod, frame); - } - if (!(left instanceof PiccodeObject)) { var err = new PiccodeException(file, line, column, "Invalid expression on the side of `.` : " + lhs + " has value " + left + " which is not an object"); err.frame = frame; @@ -112,70 +108,6 @@ public PiccodeValue execute(Integer frame) { return value; } - private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame) { - var ctx = frame == null - ? Context.top - : Context.getContextAt(frame); - - if (rhs instanceof IdentifierAst _id) { - for (var node : mod.nodes) { - if (node instanceof VarDecl vd && vd.name.equals(_id.text)) { - return node.execute(frame); - } - if (node instanceof FunctionAst func && func.name.equals(_id.text)) { - node.execute(frame); - var result = ctx.getValue(_id.text); - if (result == null) { - var err = new PiccodeException(func.file, func.line, func.column, "Function `" + _id.text + "` is not defined"); - err.frame = frame; - var nm = ctx.getSimilarName(_id.text); - if (nm != null && !nm.isEmpty()) { - var note = new PiccodeException(func.file, func.line, func.column, "Maybe you meant `" + nm + "`"); - err.addNote(note); - } - throw err; - } - return result; - } - if (node instanceof ModuleAst _mod && _mod.name.equals(_id.text)) { - node.execute(frame); - return Context.modules.get(_id.text); - } - } - - var err = new PiccodeException(file, line, column, "No function or identifier " + _id.text + " found in module " + id.text); - err.frame = frame; - throw err; - } - - var call = (CallAst) rhs; - - if (!(call.expr instanceof IdentifierAst)) { - var err = new PiccodeException(file, line, column, "Invalid function reference in module access module " + id.text + ": " + call.expr); - err.frame = frame; - throw err; - } - - var _id = (IdentifierAst) call.expr; - for (var node : mod.nodes) { - if (node instanceof VarDecl vd && vd.name.equals(_id.text)) { - return node.execute(frame); - } - if (node instanceof FunctionAst func && func.name.equals(_id.text)) { - node.execute(frame); - //return Context.top.getValue(_id.text); - return call.execute(frame); - } - if (node instanceof ModuleAst _mod && _mod.name.equals(_id.text)) { - node.execute(frame); - return Context.modules.get(_id.text); - } - } - - var err = new PiccodeException(file, line, column, "No function or identifier " + _id.text + " found in module " + id.text); - err.frame = frame; - throw err; - } private PiccodeValue processArrayIndexing(PiccodeValue[] arr, PiccodeValue execute, Integer frame) { if (!(execute instanceof PiccodeNumber)) { From f979f2a71585dfef2d7c384199c46a75c9a5eb41 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:41:43 +0200 Subject: [PATCH 5/8] FunctionAst: Now functions are store on the local table. --- src/main/java/org/piccode/ast/FunctionAst.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/piccode/ast/FunctionAst.java b/src/main/java/org/piccode/ast/FunctionAst.java index 96071b7..2cc2602 100644 --- a/src/main/java/org/piccode/ast/FunctionAst.java +++ b/src/main/java/org/piccode/ast/FunctionAst.java @@ -53,6 +53,10 @@ private String formatArgs() { @Override public PiccodeValue execute(Integer frame) { + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + Map newArgs = new HashMap<>(); var cl = new PiccodeClosure(arg, newArgs, 0, body); cl.creator = this; @@ -62,7 +66,7 @@ public PiccodeValue execute(Integer frame) { cl.file = file; cl.column = column; cl.line = line; - Context.addGlobal(name, cl); + ctx.putLocal(name, cl); return cl; } From 6e7172e76161031ebd8faa996df38650e3fce62c Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:43:47 +0200 Subject: [PATCH 6/8] ast: General improvements --- .../java/org/piccode/ast/IdentifierAst.java | 2 +- src/main/java/org/piccode/ast/ImportAst.java | 2 +- .../piccode/ast/ImportModuleCreateAst.java | 181 ++++++------------ src/main/java/org/piccode/ast/ModuleAst.java | 21 +- .../java/org/piccode/ast/PiccodeVisitor.java | 40 +--- src/main/java/org/piccode/ast/ReturnAst.java | 75 ++------ .../java/org/piccode/ast/StatementList.java | 5 +- src/main/java/org/piccode/ast/StringAst.java | 63 +++++- 8 files changed, 162 insertions(+), 227 deletions(-) diff --git a/src/main/java/org/piccode/ast/IdentifierAst.java b/src/main/java/org/piccode/ast/IdentifierAst.java index 4072ec9..b012c59 100644 --- a/src/main/java/org/piccode/ast/IdentifierAst.java +++ b/src/main/java/org/piccode/ast/IdentifierAst.java @@ -64,7 +64,7 @@ public PiccodeValue execute(Integer frame) { var note = new PiccodeSimpleNote("Track size: " + ctx.getFramesCount()); err.addNote(note); - note = new PiccodeSimpleNote("Symbol table dump: " + sb.toString()); + note = new PiccodeSimpleNote("Symbol table dump: \n" + sb.toString()); err.addNote(note); throw err; } diff --git a/src/main/java/org/piccode/ast/ImportAst.java b/src/main/java/org/piccode/ast/ImportAst.java index 9cf0269..99c689f 100644 --- a/src/main/java/org/piccode/ast/ImportAst.java +++ b/src/main/java/org/piccode/ast/ImportAst.java @@ -122,7 +122,7 @@ private void executeLifted(List moduleNodes, List nestedLifted, Intege } } - private List loadModuleFromStdLib(String module, Integer frame) { + public List loadModuleFromStdLib(String module, Integer frame) { var storage = getAppStorage(); var paths = List.of(storage, "./"); var nodes = new ArrayList(); diff --git a/src/main/java/org/piccode/ast/ImportModuleCreateAst.java b/src/main/java/org/piccode/ast/ImportModuleCreateAst.java index 9cf0269..8dd4861 100644 --- a/src/main/java/org/piccode/ast/ImportModuleCreateAst.java +++ b/src/main/java/org/piccode/ast/ImportModuleCreateAst.java @@ -18,6 +18,7 @@ import org.piccode.rt.PiccodeBoolean; import org.piccode.rt.PiccodeException; import org.piccode.rt.PiccodeInfo; +import org.piccode.rt.PiccodeModule; import org.piccode.rt.PiccodeUnit; import org.piccode.rt.PiccodeValue; @@ -25,58 +26,89 @@ * * @author hexaredecimal */ -public class ImportAst extends Ast { +public class ImportModuleCreateAst extends Ast { - public String path; - public List lifted; + public String name; + public ImportAst import_; + private String path; - public ImportAst(String path) { - this.path = path; - this.lifted = new ArrayList<>(); - } - - public ImportAst(String path, List lifted) { - this.path = path; - this.lifted = lifted; - } - - @Override - public String toString() { - return "import " + path; + public ImportModuleCreateAst(String name, ImportAst import_) { + this.name = name; + this.import_ = import_; + this.path = import_.path; } @Override public PiccodeValue execute(Integer frame) { - var nodes = loadModuleFromStdLib(path, frame); + var nodes = import_.loadModuleFromStdLib(path, frame); + + var final_nodes = new ArrayList(); + var lifted = import_.lifted; if (lifted.isEmpty()) { - nodes.forEach(node -> node.execute(frame)); - return new PiccodeUnit(); + nodes.forEach(node -> { + if (node instanceof ModuleAst mod && mod.name.equals(name)) { + final_nodes.addAll(mod.nodes); + } else { + final_nodes.add(node); + } + }); + + var top = Context.top.getValue(name); + if (top != null && top instanceof PiccodeModule module) { + final_nodes.addAll(module.nodes); + var mod = new ModuleAst(name, final_nodes); + var result = mod.execute(frame); + Context.top.putLocal(name, result); + return result; + } else { + var mod = new ModuleAst(name, final_nodes); + var result = mod.execute(frame); + return result; + } } for (var liftedNode : lifted) { - executeLifted(nodes, liftedNode, frame); + executeLifted(nodes, liftedNode, frame, final_nodes); + } + + var top = Context.top.getValue(name); + if (top != null && top instanceof PiccodeModule module) { + final_nodes.addAll(module.nodes); + var mod = new ModuleAst(name, final_nodes); + var result = mod.execute(frame); + Context.top.putLocal(name, result); + return result; + } else { + var mod = new ModuleAst(name, final_nodes); + var result = mod.execute(frame); + return result; } - return new PiccodeUnit(); } - private void executeLifted(List moduleNodes, Ast liftedNode, Integer frame) { + private void executeLifted(List moduleNodes, Ast liftedNode, Integer frame, List final_nodes) { if (liftedNode instanceof ImportId id) { for (var node : moduleNodes) { if (node instanceof ImportAst imp) { imp.execute(frame); } if (node instanceof StatementList sts) { - executeLifted(sts.nodes, id, frame); + executeLifted(sts.nodes, id, frame, final_nodes); return; } if (node instanceof FunctionAst func && func.name.equals(id.text)) { - func.execute(frame); + final_nodes.add(node); return; } if (node instanceof ModuleAst mod && mod.name.equals(id.text)) { - mod.execute(frame); + if (id.text.equals(name)) { + final_nodes.addAll(mod.nodes); + return; + } + + mod.createSymbol = false; + final_nodes.add(node); return; } } @@ -91,12 +123,12 @@ private void executeLifted(List moduleNodes, Ast liftedNode, Integer frame) imp.execute(frame); } if (node instanceof StatementList sts) { - executeLifted(sts.nodes, lift, frame); + executeLifted(sts.nodes, lift, frame, final_nodes); return; } if (node instanceof ModuleAst mod && mod.name.equals(lift.text)) { // Recursively execute lifted symbols from inside the module - executeLifted(mod.nodes, lift.nodes, frame); + executeLifted(mod.nodes, lift.nodes, frame, final_nodes); return; } if (node instanceof FunctionAst func && func.name.equals(lift.text)) { @@ -116,103 +148,14 @@ private void executeLifted(List moduleNodes, Ast liftedNode, Integer frame) } } - private void executeLifted(List moduleNodes, List nestedLifted, Integer frame) { + private void executeLifted(List moduleNodes, List nestedLifted, Integer frame, List final_nodes) { for (var lifted : nestedLifted) { - executeLifted(moduleNodes, lifted, frame); - } - } - - private List loadModuleFromStdLib(String module, Integer frame) { - var storage = getAppStorage(); - var paths = List.of(storage, "./"); - var nodes = new ArrayList(); - var _file = findModule(module, paths); - if (_file == null) { - var err = new PiccodeException(file, line, column, "Invalid module " + module.replaceAll("/", ".")); - err.frame = frame; - throw err; - } - - var path_ = _file.getPath(); - if (Context.isImportCached(path_)) { - return Context.getCached(path_); - } - - var files = _file.listFiles(); - - for (var fp : files) { - if (fp.getName().endsWith(".pics")) { - var code = readFile(fp); - if (code == null) { - var err = new PiccodeException(file, line, column, "Invalid module " + module.replaceAll("/", ".")); - err.frame = frame; - throw err; - } - var program = (StatementList) _import(fp.getAbsolutePath(), code); - var noImports = program.nodes - .stream() - .filter((value) -> { - if (value instanceof ImportAst) { - value.execute(frame); - } - return !(value instanceof ImportAst); - }) - .toList(); - nodes.addAll(noImports); - } - } - if (!Context.isImportCached(path)) { - Context.cacheImport(path, lifted); - } - return nodes; - } - - private Ast _import(String file, String code) { - Context.top.putLocal("true", new PiccodeBoolean("true")); - Context.top.putLocal("false", new PiccodeBoolean("false")); - - try { - return Compiler.program(file, code); - } catch (PiccodeException e) { - throw e; - } - } - - private String readFile(File fp) { - StringBuilder sb = new StringBuilder(); - Scanner sc; - try { - sc = new Scanner(fp); - while (sc.hasNext()) { - sb.append(sc.nextLine()).append("\n"); - } - return sb.toString(); - } catch (FileNotFoundException ex) { - return null; + executeLifted(moduleNodes, lifted, frame, final_nodes); } } @Override public String codeGen(TargetEnvironment target) { - return ""; - } - - private String getAppStorage() { - try { - String path = ImportAst.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath(); - return new File(path).getParentFile().getPath(); - } catch (URISyntaxException ex) { - return "./"; - } - } - - private File findModule(String module, List of) { - for (var dir : of) { - var fp = new File(dir + "/" + module); - if (fp.isDirectory()) { - return fp; - } - } - return null; + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody } } diff --git a/src/main/java/org/piccode/ast/ModuleAst.java b/src/main/java/org/piccode/ast/ModuleAst.java index f705f4f..bc18723 100644 --- a/src/main/java/org/piccode/ast/ModuleAst.java +++ b/src/main/java/org/piccode/ast/ModuleAst.java @@ -13,10 +13,12 @@ public class ModuleAst extends Ast { public String name; public List nodes; + public boolean createSymbol; public ModuleAst(String name, List nodes) { this.name = name; this.nodes = nodes; + this.createSymbol = true; } @Override @@ -33,15 +35,20 @@ public String toString() { @Override public PiccodeValue execute(Integer frame) { - if (Context.modules.containsKey(name)) { - var mod = Context.modules.get(name); - mod.nodes.addAll(nodes); + var ctx = Context.top; + var module = ctx.getValue(name); + + if ((module == null) || !(module instanceof PiccodeModule)) { + var mod = new PiccodeModule(name, nodes); + if (createSymbol) { + ctx.putLocal(name, mod); + } return mod; - } else { - var module = new PiccodeModule(name, nodes); - Context.modules.put(name, module); - return module; } + + var mod = (PiccodeModule) module; + mod.nodes.addAll(nodes); + return mod; } @Override diff --git a/src/main/java/org/piccode/ast/PiccodeVisitor.java b/src/main/java/org/piccode/ast/PiccodeVisitor.java index d174627..4018238 100644 --- a/src/main/java/org/piccode/ast/PiccodeVisitor.java +++ b/src/main/java/org/piccode/ast/PiccodeVisitor.java @@ -112,45 +112,15 @@ public Ast visitArg(ArgContext ctx) { var tok = ctx.ID().getSymbol(); var name = ctx.ID().getText(); if (ctx.ASSIGN() != null) { - var value = visitLiteral_expr(ctx.literal_expr()); + var value = visitExpr(ctx.expr()); var result = new Arg(name, value); - result.line = tok.getLine(); - result.column = tok.getCharPositionInLine(); - result.file = fileName; - return result; + result.export = ctx.USE() != null; + return finalizeAstNode(result, tok); } var result = new Arg(name); - result.line = tok.getLine(); - result.column = tok.getCharPositionInLine(); - result.file = fileName; - return result; - } - - @Override - public Ast visitLiteral_expr(Literal_exprContext ctx) { - if (ctx.NUMBER() != null) { - return visitNumber(ctx.NUMBER()); - } - - if (ctx.STRING() != null) { - return visitString(ctx.STRING()); - } - - if (ctx.array() != null) { - return visitArray(ctx.array()); - } - if (ctx.tuple() != null) { - return visitTuple(ctx.tuple()); - } - if (ctx.object() != null) { - return visitObject(ctx.object()); - } - - var tok = ctx.getStart(); - var err = new PiccodeException(fileName, tok.getLine(), tok.getCharPositionInLine(), "Invalid literal expression"); - err.frame = null; - throw err; + result.export = ctx.USE() != null; + return finalizeAstNode(result, tok); } @Override diff --git a/src/main/java/org/piccode/ast/ReturnAst.java b/src/main/java/org/piccode/ast/ReturnAst.java index 4072ec9..507b065 100644 --- a/src/main/java/org/piccode/ast/ReturnAst.java +++ b/src/main/java/org/piccode/ast/ReturnAst.java @@ -1,83 +1,36 @@ package org.piccode.ast; -import com.github.tomaslanger.chalk.Chalk; import org.piccode.piccodescript.TargetEnvironment; -import org.piccode.rt.Context; -import org.piccode.rt.NativeFunction; -import org.piccode.rt.PiccodeException; -import org.piccode.rt.PiccodeSimpleNote; +import org.piccode.rt.PiccodeReturnException; import org.piccode.rt.PiccodeValue; /** * * @author hexaredecimal */ -public class IdentifierAst extends Ast { +public class ReturnAst extends Ast { + public Ast expr; - public String text; - - public IdentifierAst(String text) { - this.text = text; + public ReturnAst(Ast expr) { + this.expr = expr; } - @Override - public String toString() { - return text; - } + @Override public PiccodeValue execute(Integer frame) { - var ctx = frame == null - ? Context.top - : Context.getContextAt(frame); - - - var value = ctx.getValue(text); - - if (value == null) { - var err = new PiccodeException(file, line, column, "Unknown variable `" + Chalk.on(text).red() + "` "); - err.frame = frame; - var nm = Context.top.getSimilarName(text); - if (nm != null && !nm.isEmpty()) { - var note = new PiccodeSimpleNote("Did you mean `" + Chalk.on(nm).green() + "` instead of `" + Chalk.on(text).red() + "` ?"); - err.addNote(note); - } - - var stack = ctx.getTopFrame().toMap(); - var sb = new StringBuilder(); - var entrySet = stack.entrySet(); - var size = entrySet.size(); - var index = 0; - for (var kv: entrySet) { - var key = kv.getKey(); - sb.append(key); - if (index < size - 1) { - sb.append(" ,"); - } - var str = sb.toString().length(); - if (index % 5 == 0) { - sb.append("\n"); - } - index++; - } - - var note = new PiccodeSimpleNote("Track size: " + ctx.getFramesCount()); - err.addNote(note); - - note = new PiccodeSimpleNote("Symbol table dump: " + sb.toString()); - err.addNote(note); - throw err; - } - - if (value instanceof NativeFunction nat) { - nat.frame = frame; - } - return value; + var result = expr.execute(frame); + throw new PiccodeReturnException(result); } @Override public String codeGen(TargetEnvironment target) { - return text; + return toString(); + } + + @Override + public String toString() { + return "return " + expr; } } diff --git a/src/main/java/org/piccode/ast/StatementList.java b/src/main/java/org/piccode/ast/StatementList.java index 36e0da4..f11fdee 100644 --- a/src/main/java/org/piccode/ast/StatementList.java +++ b/src/main/java/org/piccode/ast/StatementList.java @@ -29,10 +29,11 @@ public String toString() { @Override public PiccodeValue execute(Integer frame) { + PiccodeValue result = null; for (var stmt: nodes) { - stmt.execute(frame); + result = stmt.execute(frame); } - return new PiccodeBoolean("true"); + return result; } @Override diff --git a/src/main/java/org/piccode/ast/StringAst.java b/src/main/java/org/piccode/ast/StringAst.java index 6c29baa..ae41062 100644 --- a/src/main/java/org/piccode/ast/StringAst.java +++ b/src/main/java/org/piccode/ast/StringAst.java @@ -1,6 +1,9 @@ package org.piccode.ast; +import java.util.function.Consumer; +import org.piccode.backend.Compiler; import org.piccode.piccodescript.TargetEnvironment; +import org.piccode.rt.PiccodeException; import org.piccode.rt.PiccodeString; import org.piccode.rt.PiccodeValue; @@ -22,7 +25,14 @@ public String toString() { @Override public PiccodeValue execute(Integer frame) { - return new PiccodeString(unescapeString(text)); + StringBuilder finalString = new StringBuilder(); + parseInterpolatedString(text, expr -> { + var result = Compiler.program(file, expr).execute(frame).toString(); + finalString.append(result); + }, finalString); + + var str = unescapeString(finalString.toString()); + return new PiccodeString(str); } public String unescapeString(String str) { @@ -81,4 +91,55 @@ public String unescapeString(String str) { public String codeGen(TargetEnvironment target) { return String.format("\"%s\"", text); } + public void parseInterpolatedString(String input, Consumer expressionHandler, StringBuilder outputBuilder) { + int length = input.length(); + int i = 0; + + while (i < length) { + char c = input.charAt(i); + if (c == '{') { + if (i + 1 < length && input.charAt(i + 1) == '{') { + outputBuilder.append('{'); + i += 2; + continue; + } + + + int startExpr = i + 1; + int braceDepth = 1; + i++; + + while (i < length && braceDepth > 0) { + if (input.charAt(i) == '{') { + braceDepth++; + } else if (input.charAt(i) == '}') { + braceDepth--; + if (braceDepth == 0) { + break; + } + } + i++; + } + + if (braceDepth == 0) { + String expr = input.substring(startExpr, i).trim(); + expressionHandler.accept(expr); + i++; + } else { + throw new PiccodeException(file, line, column, "Unmatched '{' in input string."); + } + } + else if (c == '}') { + if (i + 1 < length && input.charAt(i + 1) == '}') { + outputBuilder.append('}'); + i += 2; + continue; + } + } else { + outputBuilder.append(c); + i++; + } + } + } + } From 65dfba917f5483922f3662a108e41afd728e3d40 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:45:12 +0200 Subject: [PATCH 7/8] antlr4: Improved the font end. --- src/main/antlr4/PiccodeScript.g4 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/antlr4/PiccodeScript.g4 b/src/main/antlr4/PiccodeScript.g4 index c29d4eb..845a287 100644 --- a/src/main/antlr4/PiccodeScript.g4 +++ b/src/main/antlr4/PiccodeScript.g4 @@ -28,7 +28,7 @@ symbol_lift symbol_entry : ID (symbol_lift)? ; -declaration: ID CC (module | func); +declaration: ID CC (module | func | import_module); module: MODULE LBRACE module_stmts RBRACE; @@ -102,11 +102,12 @@ closure_decl: BOR arg_list? BOR ARROW expr; unary: EXCLAIM expr | SUB expr + | RETURN expr | TILDE expr | BAND expr; if_expr: - IF expr LBRACE expr* RBRACE (ELSE LBRACE expr* RBRACE)?; + IF expr LBRACE expr RBRACE (ELSE LBRACE expr RBRACE)?; when_expr: WHEN expr LBRACE when_cases else_case? RBRACE; From 9e960a8ccc38d76707eaddcc27320c2cf0d01235 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sun, 29 Jun 2025 22:45:44 +0200 Subject: [PATCH 8/8] rt: Add a return exception --- .../piccode/rt/PiccodeReturnException.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/piccode/rt/PiccodeReturnException.java b/src/main/java/org/piccode/rt/PiccodeReturnException.java index ae79f47..2da348f 100644 --- a/src/main/java/org/piccode/rt/PiccodeReturnException.java +++ b/src/main/java/org/piccode/rt/PiccodeReturnException.java @@ -5,22 +5,10 @@ * * @author hexaredecimal */ -public class PiccodeUnit implements PiccodeValue { +public class PiccodeReturnException extends RuntimeException { + public PiccodeValue value; - @Override - public Object raw() { - return Void.TYPE; + public PiccodeReturnException(PiccodeValue value) { + this.value = value; } - - @Override - public String toString() { - return "()"; - } - - @Override - public String type() { - return "Unit"; - } - - }