diff --git a/vm/interp.jai b/vm/interp.jai index ce755fc..0c9d27c 100644 --- a/vm/interp.jai +++ b/vm/interp.jai @@ -13,6 +13,8 @@ Interp_Value :: struct { u: u64; f: float64; s: string; + p: *void; + proc: *Node_Procedure; } Kind :: enum { @@ -22,6 +24,8 @@ Interp_Value :: struct { int; float; string; + pointer; + procedure; } } @@ -39,7 +43,7 @@ interp_program :: (i: *Interp) { for i.toplevel if it.kind == { case .variable; var := it.(*Node_Var); - sym := var.symbol.(*Node_Symbol); + sym := var.symbol; basic.assert(!kv.exists(*i.symbols, sym.str), "redeclaring symbol '%'", sym.str); // @errors value := value_nil; @@ -50,6 +54,15 @@ interp_program :: (i: *Interp) { kv.set(*i.symbols, sym.str, value); + case .procedure; + proc := it.(*Node_Procedure); + sym := proc.symbol; + basic.assert(!kv.exists(*i.symbols, sym.str), "redeclaring procedure '%'", sym.str); + + value := make_interp_value(i, .procedure); + value.proc = proc; + kv.set(*i.symbols, sym.str, value); + case .print; print := it.(*Node_Print); expr := interp_expr(i, print.expr); @@ -81,18 +94,27 @@ interp_expr :: (i: *Interp, expr: *Node) -> *Interp_Value { // @temp sym := call.call_expr.(*Node_Symbol); basic.assert(sym.kind == .symbol); - if sym.str == { - case "add"; - basic.assert(args.count == 2, "mismatched number of arguments; require 2, given %", args.count); // @errors - node := mem.request_memory(Node_Binary,, allocator = basic.temp); - node.op = .{ kind = .plus, str = "+" }; - node.left = args[0]; - node.right = args[1]; - return interp_expr(i, node); + value, ok := kv.get(*i.symbols, sym.str); + basic.assert(ok, "procedure didn't exists '%'", sym.str); + basic.assert(value.kind == .procedure, "attempt to call non procedure '%'", sym.str); + + result := value_nil; + proc := value.proc; + + // @todo(judah): check arity, create scope, map args to locals, exec + for expr: proc.block.body { + if expr.kind == .return_ { + ret := expr.(*Node_Return); + if ret.values.count != 0 { + result = interp_expr(i, ret.values[0]); + } + + break; + } } - return value_nil; + return result; case .unary; do_unop :: (code: Code) #expand { diff --git a/vm/module.jai b/vm/module.jai index 4140cfb..ee9e815 100644 --- a/vm/module.jai +++ b/vm/module.jai @@ -24,8 +24,8 @@ strings :: #import "String"; // @future fn add(x, y) do return x + y end fn sub(x, y) do return x - y end - var x = 10.0 - var y = 20.0 + var x = 11.0 + var y = 22.0 var z = x + y * 2.0 / 3.0 var w = add(x, y) diff --git a/vm/parser.jai b/vm/parser.jai index d8537b8..460a8c3 100644 --- a/vm/parser.jai +++ b/vm/parser.jai @@ -89,8 +89,8 @@ Node_Var :: struct { #as using n: Node; n.kind = .variable; - symbol: *Node; // always *Node_Symbol - type_expr: *Node; // always *Node_Type + symbol: *Node_Symbol; + type_expr: *Node_Type; value_expr: *Node; var_flags: Var_Flag; @@ -158,18 +158,23 @@ Node_Type :: struct { type_kind: Type_Kind; union { - alias_target: *Node; + name_target: *Node_Symbol; pointer_target: *Node_Type; struct { array_element: *Node_Type; array_count: *Node; // can be null }; + struct { + procedure_arguments: [..]*Node_Type; + procedure_returns: [..]*Node_Type; + }; } Type_Kind :: enum { - alias; + named; pointer; array; + procedure; } } @@ -177,29 +182,25 @@ Node_Procedure :: struct { #as using n: Node; n.kind = .procedure; - header: *Node_Procedure_Header; + arguments: [..]Parameter; + returns: [..]Parameter; - args: [..]Node_Parameter; - rets: [..]Node_Parameter; - body: *Node_Block; - flags: Flag; + symbol: *Node_Symbol; // can be null + head: *Node_Type; // will always be of type .procedure + block: *Node_Block; + flags: Flag; Flag :: enum_flags { must_inline; } } -Node_Parameter :: struct { +Parameter :: struct { symbol: *Node_Symbol; type: *Node_Type; value: *Node; // always an expression, can be null } -Node_Procedure_Header :: struct { - args: [..]*Node_Type; - rets: [..]*Node_Type; -} - Node_Print :: struct { #as using n: Node; n.kind = .print; @@ -211,14 +212,15 @@ Node_Procedure_Call :: struct { #as using n: Node; n.kind = .procedure_call; - call_expr: *Node; + call_expr: *Node; named_arguments: kv.Kv(*Node, *Node); - all_arguments: [..]*Node; + all_arguments: [..]*Node; } Node_Block :: struct { #as using n: Node; n.kind = .block; + body: [..]*Node; } @@ -277,7 +279,7 @@ parse_toplevel :: (p: *Parser) -> *Node { s:, ok = expect_token(p, .symbol); basic.assert(ok, "symbol"); // @errors - type_expr: *Node; + type_expr: *Node_Type; value_expr: *Node; is_const := t.kind == .kw_def; @@ -316,7 +318,6 @@ parse_toplevel :: (p: *Parser) -> *Node { // return expr0, ..exprN case .kw_return; node := make_node(p, Node_Return); - array.init(*node.values, p.allocator); prev_offset := p.offset; expr := parse_expression(p); @@ -338,7 +339,7 @@ parse_toplevel :: (p: *Parser) -> *Node { node.expr = expr; return node; - // fn symbol(arg0, ..argN) do end + // fn symbol(arg0, ..argN) do ... end case .kw_fn; symbol, ok := expect_token(p, .symbol); basic.assert(ok, "expected name for procedure"); // @errors @todo(judah): lambdas @@ -346,12 +347,20 @@ parse_toplevel :: (p: *Parser) -> *Node { t, ok = expect_token(p, .l_paren); basic.assert(ok, "expected '(' but found '%'", t.str); // @errors + node := make_node(p, Node_Procedure); + node.symbol = make_node(p, Node_Symbol); + node.symbol.str = symbol.str; + while !at_end(p) { t = peek_token(p); if t.kind == .r_paren break; - expr := parse_expression(p); - basic.assert(expr != null); // @errors + sym, ok := expect_token(p, .symbol); + basic.assert(ok, "expected symbol"); // @errors + + arg := array.append(*node.arguments); + arg.symbol = make_node(p, Node_Symbol); + arg.symbol.str = sym.str; t = peek_token(p); if t.kind == { @@ -368,12 +377,10 @@ parse_toplevel :: (p: *Parser) -> *Node { _, ok = expect_token(p, .r_paren); basic.assert(ok, "expected ')'"); // @errors - block := parse_block(p); - basic.assert(block != null, "expected block"); // @errors + node.block = parse_block(p); + basic.assert(node.block != null, "expected block"); // @errors - node := make_node(p, Node_Procedure); - - return null; + return node; } return null; @@ -384,7 +391,6 @@ parse_block :: (p: *Parser) -> *Node_Block { basic.assert(ok, "expected 'do' found '%'", t.str); // @errors block := make_node(p, Node_Block); - array.init(*block.body, p.allocator); while !at_end(p) { t = peek_token(p); @@ -411,14 +417,12 @@ parse_type_expression :: (p: *Parser) -> *Node_Type { target := parse_type_expression(p); basic.assert(target != null, "pointer target"); // @errors - node := make_node(p, Node_Type); - node.type_kind = .pointer; + node := make_node(p, .pointer); node.pointer_target = target; return node; case .l_square; - node := make_node(p, Node_Type); - node.type_kind = .array; + node := make_node(p, .array); // slice if peek_token(p).kind == .r_square { @@ -449,9 +453,8 @@ parse_type_expression :: (p: *Parser) -> *Node_Type { symbol := make_node(p, Node_Symbol); symbol.str = t.str; - node := make_node(p, Node_Type); - node.type_kind = .alias; - node.alias_target = symbol; + node := make_node(p, .named); + node.name_target = symbol; return node; } @@ -540,9 +543,6 @@ parse_expression_postfix :: (p: *Parser) -> *Node { node := make_node(p, Node_Procedure_Call); node.call_expr = base; - array.init(*node.all_arguments, p.allocator); - kv.init(*node.named_arguments, p.allocator); - while !at_end(p) { t = peek_token(p); if t.kind == .r_paren break; @@ -641,7 +641,35 @@ parse_expression_base :: (p: *Parser) -> *Node { } make_node :: (p: *Parser, $T: Type) -> *T { - return mem.request_memory(T,, allocator = p.allocator); + node := mem.request_memory(T,, allocator = p.allocator); + + #if T == { // nodes that require initialization + case Node_Block; + array.init(*node.body, p.allocator); + case Node_Return; + array.init(*node.values, p.allocator); + case Node_Procedure_Call; + array.init(*node.all_arguments, p.allocator); + kv.init(*node.named_arguments, p.allocator); + case Node_Procedure; + array.init(*node.arguments, p.allocator); + array.init(*node.returns, p.allocator); + } + + return node; +} + +make_node :: (p: *Parser, $type_kind: Node_Type.Type_Kind) -> *Node_Type { + type := mem.request_memory(Node_Type,, allocator = p.allocator); + type.type_kind = type_kind; + + #if type_kind == { + case .procedure; + array.init(*type.procedure_arguments, p.allocator); + array.init(*type.procedure_returns, p.allocator); + } + + return type; } peek_token :: (p: *Parser) -> Token {