diff --git a/vm/interp.jai b/vm/interp.jai index cbc9a12..0b1a15f 100644 --- a/vm/interp.jai +++ b/vm/interp.jai @@ -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; diff --git a/vm/module.jai b/vm/module.jai index 21f78f9..324dcfe 100644 --- a/vm/module.jai +++ b/vm/module.jai @@ -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; diff --git a/vm/parser.jai b/vm/parser.jai index 460a8c3..1f0ca5b 100644 --- a/vm/parser.jai +++ b/vm/parser.jai @@ -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);