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; s: string;
p: *void; p: *void;
proc: *Node_Procedure; proc: *Node_Procedure;
val: *Interp_Value;
} }
Kind :: enum { Kind :: enum {
@ -31,6 +32,7 @@ Interp_Value :: struct {
string; string;
pointer; pointer;
procedure; procedure;
value;
} }
} }
@ -47,24 +49,44 @@ init :: (i: *Interp, allocator: Allocator) {
} }
interp_program :: (i: *Interp) { 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; case .variable;
var := it.(*Node_Var); var := stmt.(*Node_Var);
sym := var.symbol; sym := var.symbol;
basic.assert(!kv.exists(*scope.bindings, sym.str), "redeclaring symbol '%'", sym.str); // @errors basic.assert(!kv.exists(*scope.bindings, sym.str), "redeclaring symbol '%'", sym.str); // @errors
value := value_nil; value := value_nil;
if var.value_expr != null { 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 basic.assert(value != null); // @errors
} }
kv.set(*scope.bindings, sym.str, value); 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; case .procedure;
proc := it.(*Node_Procedure); proc := stmt.(*Node_Procedure);
sym := proc.symbol; sym := proc.symbol;
basic.assert(!kv.exists(*scope.bindings, sym.str), "redeclaring procedure '%'", sym.str); 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); kv.set(*scope.bindings, sym.str, value);
case .print; case .print;
print := it.(*Node_Print); print := stmt.(*Node_Print);
expr := interp_expr(i, print.expr, i.global); expr := interp_expr(i, print.expr, scope);
if expr == null continue; if expr == null return;
if expr.kind == { if expr.kind == {
case .none; // do nothing case .none; // do nothing
@ -90,10 +112,27 @@ interp_program :: (i: *Interp) {
basic.print("\n"); basic.print("\n");
case; 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 { interp_expr :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Value {
if expr.kind == { if expr.kind == {
case .procedure_call; case .procedure_call;
@ -102,7 +141,7 @@ interp_expr :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Value
// @temp // @temp
sym := call.call_expr.(*Node_Symbol); sym := call.call_expr.(*Node_Symbol);
basic.assert(sym.kind == .symbol); basic.assert(sym.kind == .symbol, "%", sym.kind);
value := find_symbol(scope, sym.str); value := find_symbol(scope, sym.str);
basic.assert(value != null, "procedure didn't exists '%'", 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; break;
} }
else {
interp_statement(i, expr, proc_scope);
}
} }
return result; return result;

View file

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

View file

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