Skip to content

Commit db7f8ec

Browse files
committed
ast: Clean up the code and make it safer. This also adds the implementation of annotations
1 parent 797a4e8 commit db7f8ec

File tree

9 files changed

+169
-179
lines changed

9 files changed

+169
-179
lines changed

src/main/java/org/piccode/ast/CCOperationAst.java

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -37,45 +37,47 @@ public String toString() {
3737

3838
@Override
3939
public PiccodeValue execute(Integer frame) {
40-
if (lhs instanceof CCOperationAst op) {
41-
var mod = (PiccodeModule) op.execute(frame);
42-
if (!(rhs instanceof CallAst) && !(rhs instanceof IdentifierAst)) {
43-
throw new PiccodeException(file, line, column, "No node " + rhs + " found in module " + mod.name);
40+
return Ast.safeExecute(frame, this, (expr) -> {
41+
if (lhs instanceof CCOperationAst op) {
42+
var mod = (PiccodeModule) op.execute(frame);
43+
if (!(rhs instanceof CallAst) && !(rhs instanceof IdentifierAst)) {
44+
throw new PiccodeException(file, line, column, "No node " + rhs + " found in module " + Chalk.on(mod.name).green());
45+
}
46+
47+
var id = new IdentifierAst(mod.name);
48+
id.file = file;
49+
id.line = line;
50+
id.column = column;
51+
return process(id, mod, frame);
4452
}
45-
46-
var id = new IdentifierAst(mod.name);
47-
id.file = file;
48-
id.line = line;
49-
id.column = column;
50-
return process(id, mod, frame);
51-
}
52-
53-
if (lhs instanceof IdentifierAst id && Context.top.getValue(id.text) != null) {
54-
var mod = Context.top.getValue(id.text);
55-
if (!(rhs instanceof CallAst) && !(rhs instanceof IdentifierAst)) {
56-
throw new PiccodeException(file, line, column, "No node " + rhs + " found in module " + id.text);
53+
54+
if (lhs instanceof IdentifierAst id && Context.top.getValue(id.text) != null) {
55+
var mod = Context.top.getValue(id.text);
56+
if (!(rhs instanceof CallAst) && !(rhs instanceof IdentifierAst)) {
57+
throw new PiccodeException(file, line, column, "No node " + rhs + " found in module " + Chalk.on(id.text).green());
58+
}
59+
return process(id, (PiccodeModule) mod, frame);
5760
}
58-
return process(id, (PiccodeModule)mod, frame);
59-
}
6061

61-
var err = new PiccodeException(file, line, column, "Invalid use of `::`. Expected a module on the lhs, but found " + Chalk.on(lhs.toString()).red());
62-
err.frame = frame;
62+
var err = new PiccodeException(file, line, column, "Invalid use of `::`. Expected a module on the lhs, but found " + Chalk.on(lhs.toString()).red());
63+
err.frame = frame;
6364

64-
if (lhs instanceof IdentifierAst id) {
65-
var nm = Context.top.getSimilarName(id.text);
66-
if (nm != null && !nm.isEmpty()) {
67-
var note = new PiccodeSimpleNote("Did you mean `" + Chalk.on(nm).green() + "` instead of `" + Chalk.on(id.text).red() + "` ?");
68-
err.addNote(note);
65+
if (lhs instanceof IdentifierAst id) {
66+
var nm = Context.top.getSimilarName(id.text);
67+
if (nm != null && !nm.isEmpty()) {
68+
var note = new PiccodeSimpleNote("Did you mean `" + Chalk.on(nm).green() + "` instead of `" + Chalk.on(id.text).red() + "` ?");
69+
err.addNote(note);
70+
}
6971
}
70-
}
71-
throw err;
72+
throw err;
73+
});
7274
}
7375

7476
private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame) {
7577
var ctx = frame == null
76-
? Context.top
77-
: Context.getContextAt(frame);
78-
78+
? Context.top
79+
: Context.getContextAt(frame);
80+
7981
if (rhs instanceof IdentifierAst _id) {
8082
for (var node : mod.nodes) {
8183
if (node instanceof VarDecl vd && vd.name.equals(_id.text)) {
@@ -85,11 +87,11 @@ private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame)
8587
node.execute(frame);
8688
var result = ctx.getValue(_id.text);
8789
if (result == null) {
88-
var err = new PiccodeException(func.file, func.line, func.column, "Function `" + _id.text + "` is not defined");
90+
var err = new PiccodeException(func.file, func.line, func.column, "Function `" + Chalk.on(_id.text).red() + "` is not defined");
8991
err.frame = frame;
9092
var nm = ctx.getSimilarName(_id.text);
9193
if (nm != null && !nm.isEmpty()) {
92-
var note = new PiccodeException(func.file, func.line, func.column, "Maybe you meant `" + nm + "`");
94+
var note = new PiccodeException(func.file, func.line, func.column, "Maybe you meant `" + Chalk.on(nm).green() + "`");
9395
err.addNote(note);
9496
}
9597
throw err;
@@ -101,15 +103,15 @@ private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame)
101103
}
102104
}
103105

104-
var err = new PiccodeException(file, line, column, "No function or identifier " + _id.text + " found in module " + id.text);
106+
var err = new PiccodeException(file, line, column, "No function or identifier " + Chalk.on(_id.text).red() + " found in module " + Chalk.on(id.text).green());
105107
err.frame = frame;
106108
throw err;
107109
}
108110

109111
var call = (CallAst) rhs;
110112

111113
if (!(call.expr instanceof IdentifierAst)) {
112-
var err = new PiccodeException(file, line, column, "Invalid function reference in module access module " + id.text + ": " + call.expr);
114+
var err = new PiccodeException(file, line, column, "Invalid function reference in module access module " + Chalk.on(id.text).red() + ": " + call.expr);
113115
err.frame = frame;
114116
throw err;
115117
}
@@ -120,7 +122,7 @@ private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame)
120122
return node.execute(frame);
121123
}
122124
if (node instanceof FunctionAst func && func.name.equals(_id.text)) {
123-
return safeExecute(frame, func, (expr) -> {
125+
return Ast.safeExecute(frame, func, (expr) -> {
124126
node.execute(frame);
125127
return call.execute(frame);
126128
});
@@ -131,7 +133,7 @@ private PiccodeValue process(IdentifierAst id, PiccodeModule mod, Integer frame)
131133
}
132134
}
133135

134-
var err = new PiccodeException(file, line, column, "No function or identifier " + _id.text + " found in module " + id.text);
136+
var err = new PiccodeException(file, line, column, "No function or identifier " + Chalk.on(_id.text).red() + " found in module " + Chalk.on(id.text).green());
135137
err.frame = frame;
136138
throw err;
137139
}
@@ -141,17 +143,4 @@ public String codeGen(TargetEnvironment target) {
141143
return String.format("%s.%s", lhs, rhs);
142144
}
143145

144-
private PiccodeValue safeExecute(Integer frame, Ast expr, Function<Ast, PiccodeValue> func) {
145-
var ctx = frame == null
146-
? Context.top
147-
: Context.getContextAt(frame);
148-
149-
try {
150-
ctx.pushStackFrame(expr);
151-
return func.apply(expr);
152-
} catch (PiccodeReturnException | PiccodeException exception) {
153-
ctx.dropStackFrame();
154-
throw exception;
155-
}
156-
}
157146
}

src/main/java/org/piccode/ast/CallAst.java

Lines changed: 63 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -41,87 +41,91 @@ public String toString() {
4141

4242
@Override
4343
public PiccodeValue execute(Integer frame) {
44-
var expr_val = expr.execute(frame);
45-
if (!(expr_val instanceof PiccodeClosure) && !(expr_val instanceof NativeFunction)) {
46-
var err = new PiccodeException(file, line, column, "Attempt to call a non-callable expression. Issue is: " + expr + " = " + expr_val);
47-
err.frame = frame;
48-
throw err;
49-
}
50-
lastCall = expr;
44+
return Ast.safeExecute(frame, this, ($_ignored_$) -> {
45+
var expr_val = expr.execute(frame);
46+
if (!(expr_val instanceof PiccodeClosure) && !(expr_val instanceof NativeFunction)) {
47+
var err = new PiccodeException(file, line, column, "Attempt to call a non-callable expression. Issue is: " + expr + " = " + expr_val);
48+
err.frame = frame;
49+
throw err;
50+
}
51+
lastCall = expr;
52+
53+
if (expr_val instanceof NativeFunction nat) {
54+
nat.frame = frame;
55+
nat.file = file;
56+
nat.line = line;
57+
nat.column = column;
58+
for (var node : nodes) {
59+
if (node instanceof NamedCallArg named) {
60+
nat = (NativeFunction) nat.callNamed(named.name, named.value.execute(frame));
61+
nat.frame = frame;
62+
nat.file = file;
63+
nat.line = line;
64+
nat.column = column;
65+
} else {
66+
nat = (NativeFunction) nat.call(node.execute(frame));
67+
nat.frame = frame;
68+
nat.file = file;
69+
nat.line = line;
70+
nat.column = column;
71+
}
72+
}
73+
74+
var result = nat.evaluateIfReady();
75+
return result;
76+
}
77+
78+
var closure = (PiccodeClosure) expr_val;
79+
closure.callSite = new Ast.Location(line, column);
80+
closure.callSiteFile = file;
81+
closure.frame = frame;
5182

52-
if (expr_val instanceof NativeFunction nat) {
53-
nat.frame = frame;
54-
nat.file = file;
55-
nat.line = line;
56-
nat.column = column;
5783
for (var node : nodes) {
84+
var clauses = closure.clauses;
5885
if (node instanceof NamedCallArg named) {
59-
nat = (NativeFunction) nat.callNamed(named.name, named.value.execute(frame));
60-
nat.frame = frame;
61-
nat.file = file;
62-
nat.line = line;
63-
nat.column = column;
86+
closure = (PiccodeClosure) closure.callNamed(named.name, named.value.execute(frame));
87+
closure.callSite = new Ast.Location(line, column);
88+
closure.callSiteFile = file;
89+
closure.frame = frame;
90+
closure.clauses = clauses;
6491
} else {
65-
nat = (NativeFunction) nat.call(node.execute(frame));
66-
nat.frame = frame;
67-
nat.file = file;
68-
nat.line = line;
69-
nat.column = column;
92+
closure = (PiccodeClosure) closure.call(node.execute(frame));
93+
closure.callSite = new Ast.Location(line, column);
94+
closure.callSiteFile = file;
95+
closure.frame = frame;
96+
closure.clauses = clauses;
7097
}
7198
}
7299

73-
var result = nat.evaluateIfReady();
100+
// Evaluate only if fully applied
101+
var result = closure.evaluateIfReady();
74102
return result;
75-
}
76-
77-
var closure = (PiccodeClosure) expr_val;
78-
closure.callSite = new Ast.Location(line, column);
79-
closure.callSiteFile = file;
80-
closure.frame = frame;
81-
82-
for (var node : nodes) {
83-
var clauses = closure.clauses;
84-
if (node instanceof NamedCallArg named) {
85-
closure = (PiccodeClosure) closure.callNamed(named.name, named.value.execute(frame));
86-
closure.callSite = new Ast.Location(line, column);
87-
closure.callSiteFile = file;
88-
closure.frame = frame;
89-
closure.clauses = clauses;
90-
} else {
91-
closure = (PiccodeClosure) closure.call(node.execute(frame));
92-
closure.callSite = new Ast.Location(line, column);
93-
closure.callSiteFile = file;
94-
closure.frame = frame;
95-
closure.clauses = clauses;
96-
}
97-
}
98-
99-
// Evaluate only if fully applied
100-
var result = closure.evaluateIfReady();
101-
return result;
103+
});
102104
}
103105

104106
@Override
105107
public String codeGen(TargetEnvironment target) {
106108
return switch (target) {
107-
case JS -> codegenJSCall(target);
108-
default -> "todo";
109+
case JS ->
110+
codegenJSCall(target);
111+
default ->
112+
"todo";
109113
};
110114
}
111115

112116
private String codegenJSCall(TargetEnvironment env) {
113117
var sb = new StringBuilder()
114-
.append("(")
115-
.append(expr.codeGen(env))
116-
.append(")");
118+
.append("(")
119+
.append(expr.codeGen(env))
120+
.append(")");
117121

118122
nodes.forEach(node -> {
119123
sb
120-
.append("(")
121-
.append(node.codeGen(env))
122-
.append(")");
124+
.append("(")
125+
.append(node.codeGen(env))
126+
.append(")");
123127
});
124-
128+
125129
return sb.toString();
126130
}
127131

src/main/java/org/piccode/ast/ClosureAst.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@ public class ClosureAst extends Ast {
2020
public ClosureAst(List<Ast> args, Ast body) {
2121
this.args = args;
2222
this.body = body;
23-
if (args == null || args.isEmpty()) {
24-
var loc = Ast.getLocation(body);
25-
this.line = loc.line;
26-
this.column = loc.col;
27-
} else {
28-
var arg = args.getFirst();
29-
this.line = arg.line;
30-
this.column = arg.column;
31-
}
3223
}
3324

3425

src/main/java/org/piccode/ast/FunctionAst.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class FunctionAst extends Ast {
2121
public List<Ast> arg;
2222
public Ast body;
2323
public List<ClauseAst> clauses = new ArrayList<>();
24+
public List<String> annotations = new ArrayList<>();
2425

2526
public FunctionAst(String name, List<Ast> arg, Ast body) {
2627
this.name = name;
@@ -69,6 +70,7 @@ public PiccodeValue execute(Integer frame) {
6970
cl.file = file;
7071
cl.column = column;
7172
cl.line = line;
73+
cl.annotations = annotations;
7274
var value = ctx.getValue(name);
7375
if (value == null) {
7476
if (!clauses.isEmpty()) {
@@ -93,6 +95,15 @@ public PiccodeValue execute(Integer frame) {
9395
}
9496
clauses.clear();
9597
}
98+
if (closure.annotations.isEmpty()) {
99+
closure.annotations = annotations;
100+
} else {
101+
for (var anot: annotations) {
102+
if (!closure.annotations.contains(anot)) {
103+
closure.annotations.add(anot);
104+
}
105+
}
106+
}
96107
closure.clauses.add(new ClauseAst(arg, body));
97108
return closure;
98109
}

src/main/java/org/piccode/ast/IdentifierAst.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,19 @@ public PiccodeValue execute(Integer frame) {
9090
index++;
9191
}
9292

93-
var note = new PiccodeSimpleNote("Stack size: " + ctx.getFramesCount());
93+
var sz = ctx.getFramesCount();
94+
var note = new PiccodeSimpleNote("Stack size: " + sz);
9495
err.addNote(note);
9596

97+
if (sz > 0) {
98+
var _sb = new StringBuilder();
99+
for (var _frame: ctx.getCallStack()) {
100+
_sb.append(_frame.caller).append("\n");
101+
}
102+
note = new PiccodeSimpleNote("Stack dump: \n" + _sb.toString());
103+
err.addNote(note);
104+
}
105+
96106
note = new PiccodeSimpleNote("Symbol table dump: \n" + sb.toString());
97107
err.addNote(note);
98108
throw err;

src/main/java/org/piccode/ast/LetInExprAst.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,14 @@ public String toString() {
3939

4040
@Override
4141
public PiccodeValue execute(Integer frame) {
42-
return evaluate(frame, () -> {
42+
return Ast.safeExecute(frame, this, (func) -> {
4343
for (var decl : vars) {
4444
decl.execute(frame);
4545
}
46-
return evaluate(frame, () -> expr.execute(frame));
46+
return Ast.safeExecute(frame, () -> expr.execute(frame));
4747
});
4848
}
4949

50-
private PiccodeValue evaluate(Integer frame, Supplier<PiccodeValue> fx) {
51-
var ctx = frame == null
52-
? Context.top
53-
: Context.getContextAt(frame);
54-
ctx.pushScope();
55-
try {
56-
return fx.get();
57-
} catch (PiccodeReturnException | PiccodeException e) {
58-
ctx.dropScope();
59-
throw e;
60-
}
61-
}
6250

6351
@Override
6452
public String codeGen(TargetEnvironment target) {

0 commit comments

Comments
 (0)