improvements

This commit is contained in:
Judah Caruso 2025-06-26 21:09:03 -06:00
parent 3bfa0679ae
commit 3f81359ab1
3 changed files with 105 additions and 21 deletions

View file

@ -20,6 +20,7 @@ Interp_Value :: struct {
s: string;
p: *void;
proc: *Node_Procedure;
val: *Interp_Value;
}
Kind :: enum {
@ -31,6 +32,7 @@ Interp_Value :: struct {
string;
pointer;
procedure;
value;
}
}
@ -47,24 +49,44 @@ init :: (i: *Interp, allocator: Allocator) {
}
interp_program :: (i: *Interp) {
scope := i.global;
for i.toplevel {
interp_statement(i, it, i.global);
}
}
for i.toplevel if it.kind == {
interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
if stmt.kind == {
case .variable;
var := it.(*Node_Var);
var := stmt.(*Node_Var);
sym := var.symbol;
basic.assert(!kv.exists(*scope.bindings, sym.str), "redeclaring symbol '%'", sym.str); // @errors
value := value_nil;
if var.value_expr != null {
value = interp_expr(i, var.value_expr, i.global);
value = interp_expr(i, var.value_expr, scope);
basic.assert(value != null); // @errors
}
kv.set(*scope.bindings, sym.str, value);
case .assign;
assign := stmt.(*Node_Assign);
src := interp_expr(i, assign.src, scope);
basic.assert(src != null); // @errors
dst := interp_lvalue(i, assign.dst, scope);
basic.assert(dst != null); // @errors
basic.assert(dst.kind == .value); // @errors
// @todo: typechecking
if assign.op.kind == {
case .equal;
dst.val.* = src.*;
}
case .procedure;
proc := it.(*Node_Procedure);
proc := stmt.(*Node_Procedure);
sym := proc.symbol;
basic.assert(!kv.exists(*scope.bindings, sym.str), "redeclaring procedure '%'", sym.str);
@ -73,9 +95,9 @@ interp_program :: (i: *Interp) {
kv.set(*scope.bindings, sym.str, value);
case .print;
print := it.(*Node_Print);
expr := interp_expr(i, print.expr, i.global);
if expr == null continue;
print := stmt.(*Node_Print);
expr := interp_expr(i, print.expr, scope);
if expr == null return;
if expr.kind == {
case .none; // do nothing
@ -90,10 +112,27 @@ interp_program :: (i: *Interp) {
basic.print("\n");
case;
basic.assert(false, "unhandled node kind: %", it.kind); // @errors
interp_expr(i, stmt, scope);
// basic.assert(false, "unhandled node kind: %", stmt.kind); // @errors
}
}
interp_lvalue :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Value {
if expr.kind == {
case .symbol;
sym := expr.(*Node_Symbol);
lval := find_symbol(scope, sym.str);
oval := make_interp_value(i, .value);
oval.val = lval;
return oval;
case;
basic.assert(false, "unable to get lvalue from %", expr.kind);
}
return null;
}
interp_expr :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Value {
if expr.kind == {
case .procedure_call;
@ -102,7 +141,7 @@ interp_expr :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Value
// @temp
sym := call.call_expr.(*Node_Symbol);
basic.assert(sym.kind == .symbol);
basic.assert(sym.kind == .symbol, "%", sym.kind);
value := find_symbol(scope, sym.str);
basic.assert(value != null, "procedure didn't exists '%'", sym.str);
@ -126,6 +165,9 @@ interp_expr :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Value
break;
}
else {
interp_statement(i, expr, proc_scope);
}
}
return result;

View file

@ -21,14 +21,14 @@ strings :: #import "String"; // @future
init(*parser, context.allocator);
ok := parse_string(*parser, #string END
fn add(x, y) do return x + y end
fn add(a, b) do return a + b end
fn sub(x, y) do return x - y end
var x = 11.0
var y = 22.0
print add(x, y)
print add(x+1.0, y)
add(1.0, 1.0)
// print add(x+1.0, y)
END);
interp: Interp;

View file

@ -67,6 +67,7 @@ Node :: struct {
stmt_start;
print;
return_;
assign;
stmt_end;
decl_start;
@ -99,6 +100,15 @@ Node_Var :: struct {
}
}
Node_Assign :: struct {
#as using n: Node;
n.kind = .assign;
op: Token;
dst: *Node;
src: *Node;
}
Node_Unary :: struct {
#as using n: Node;
n.kind = .unary;
@ -256,7 +266,7 @@ parse_string :: (p: *Parser, source: string) -> bool {
break;
}
node := parse_toplevel(p);
node := parse_statement(p);
if node != null array.append(*p.toplevel, node);
}
@ -266,17 +276,17 @@ parse_string :: (p: *Parser, source: string) -> bool {
#scope_file;
parse_toplevel :: (p: *Parser) -> *Node {
t, ok := expect_token(p, .kw_var, .kw_def, .kw_fn, .kw_print, .kw_do, .kw_return);
basic.assert(ok, "var, def, print, found '%'", t.str); // @errors
parse_statement :: (p: *Parser) -> *Node {
t := peek_token(p);
if t.kind == {
// var sym type_expr
// var sym type_expr = expr
// var sym = expr
case .kw_var; #through;
case .kw_def;
s:, ok = expect_token(p, .symbol);
consume_token(p);
s, ok := expect_token(p, .symbol);
basic.assert(ok, "symbol"); // @errors
type_expr: *Node_Type;
@ -317,6 +327,8 @@ parse_toplevel :: (p: *Parser) -> *Node {
// return
// return expr0, ..exprN
case .kw_return;
consume_token(p);
node := make_node(p, Node_Return);
prev_offset := p.offset;
@ -332,6 +344,8 @@ parse_toplevel :: (p: *Parser) -> *Node {
// print(expr)
// print expr
case .kw_print;
consume_token(p);
expr := parse_expression(p);
basic.assert(expr != null, "expected expression"); // @errors
@ -341,6 +355,8 @@ parse_toplevel :: (p: *Parser) -> *Node {
// fn symbol(arg0, ..argN) do ... end
case .kw_fn;
consume_token(p);
symbol, ok := expect_token(p, .symbol);
basic.assert(ok, "expected name for procedure"); // @errors @todo(judah): lambdas
@ -381,9 +397,35 @@ parse_toplevel :: (p: *Parser) -> *Node {
basic.assert(node.block != null, "expected block"); // @errors
return node;
// do ... end
case .kw_do;
return parse_block(p);
}
return null;
return parse_simple_statement(p);
}
parse_simple_statement :: (p: *Parser) -> *Node {
dst := parse_expression(p);
basic.assert(dst != null, "expected expression for simple statement");
t := peek_token(p);
if t.kind == {
case .equal;
consume_token(p);
src := parse_expression(p);
basic.assert(src != null, "expected right-hand side of assignment");
node := make_node(p, Node_Assign);
node.op = t;
node.dst = dst;
node.src = src;
return node;
}
return dst;
}
parse_block :: (p: *Parser) -> *Node_Block {
@ -396,7 +438,7 @@ parse_block :: (p: *Parser) -> *Node_Block {
t = peek_token(p);
if t.kind == .kw_end break;
node := parse_toplevel(p);
node := parse_statement(p);
basic.assert(node != null); // @errors
array.append(*block.body, node);