[vm] more procedure things
This commit is contained in:
parent
7e685785be
commit
b1a9e84d8b
3 changed files with 101 additions and 51 deletions
|
|
@ -13,6 +13,8 @@ Interp_Value :: struct {
|
||||||
u: u64;
|
u: u64;
|
||||||
f: float64;
|
f: float64;
|
||||||
s: string;
|
s: string;
|
||||||
|
p: *void;
|
||||||
|
proc: *Node_Procedure;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kind :: enum {
|
Kind :: enum {
|
||||||
|
|
@ -22,6 +24,8 @@ Interp_Value :: struct {
|
||||||
int;
|
int;
|
||||||
float;
|
float;
|
||||||
string;
|
string;
|
||||||
|
pointer;
|
||||||
|
procedure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,7 +43,7 @@ interp_program :: (i: *Interp) {
|
||||||
for i.toplevel if it.kind == {
|
for i.toplevel if it.kind == {
|
||||||
case .variable;
|
case .variable;
|
||||||
var := it.(*Node_Var);
|
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
|
basic.assert(!kv.exists(*i.symbols, sym.str), "redeclaring symbol '%'", sym.str); // @errors
|
||||||
|
|
||||||
value := value_nil;
|
value := value_nil;
|
||||||
|
|
@ -50,6 +54,15 @@ interp_program :: (i: *Interp) {
|
||||||
|
|
||||||
kv.set(*i.symbols, sym.str, value);
|
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;
|
case .print;
|
||||||
print := it.(*Node_Print);
|
print := it.(*Node_Print);
|
||||||
expr := interp_expr(i, print.expr);
|
expr := interp_expr(i, print.expr);
|
||||||
|
|
@ -81,18 +94,27 @@ interp_expr :: (i: *Interp, expr: *Node) -> *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);
|
||||||
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);
|
value, ok := kv.get(*i.symbols, sym.str);
|
||||||
node.op = .{ kind = .plus, str = "+" };
|
basic.assert(ok, "procedure didn't exists '%'", sym.str);
|
||||||
node.left = args[0];
|
basic.assert(value.kind == .procedure, "attempt to call non procedure '%'", sym.str);
|
||||||
node.right = args[1];
|
|
||||||
return interp_expr(i, node);
|
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;
|
case .unary;
|
||||||
do_unop :: (code: Code) #expand {
|
do_unop :: (code: Code) #expand {
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ strings :: #import "String"; // @future
|
||||||
fn add(x, y) do return x + y end
|
fn add(x, y) do return x + y end
|
||||||
fn sub(x, y) do return x - y end
|
fn sub(x, y) do return x - y end
|
||||||
|
|
||||||
var x = 10.0
|
var x = 11.0
|
||||||
var y = 20.0
|
var y = 22.0
|
||||||
var z = x + y * 2.0 / 3.0
|
var z = x + y * 2.0 / 3.0
|
||||||
var w = add(x, y)
|
var w = add(x, y)
|
||||||
|
|
||||||
|
|
|
||||||
106
vm/parser.jai
106
vm/parser.jai
|
|
@ -89,8 +89,8 @@ Node_Var :: struct {
|
||||||
#as using n: Node;
|
#as using n: Node;
|
||||||
n.kind = .variable;
|
n.kind = .variable;
|
||||||
|
|
||||||
symbol: *Node; // always *Node_Symbol
|
symbol: *Node_Symbol;
|
||||||
type_expr: *Node; // always *Node_Type
|
type_expr: *Node_Type;
|
||||||
value_expr: *Node;
|
value_expr: *Node;
|
||||||
var_flags: Var_Flag;
|
var_flags: Var_Flag;
|
||||||
|
|
||||||
|
|
@ -158,18 +158,23 @@ Node_Type :: struct {
|
||||||
type_kind: Type_Kind;
|
type_kind: Type_Kind;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
alias_target: *Node;
|
name_target: *Node_Symbol;
|
||||||
pointer_target: *Node_Type;
|
pointer_target: *Node_Type;
|
||||||
struct {
|
struct {
|
||||||
array_element: *Node_Type;
|
array_element: *Node_Type;
|
||||||
array_count: *Node; // can be null
|
array_count: *Node; // can be null
|
||||||
};
|
};
|
||||||
|
struct {
|
||||||
|
procedure_arguments: [..]*Node_Type;
|
||||||
|
procedure_returns: [..]*Node_Type;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Kind :: enum {
|
Type_Kind :: enum {
|
||||||
alias;
|
named;
|
||||||
pointer;
|
pointer;
|
||||||
array;
|
array;
|
||||||
|
procedure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,29 +182,25 @@ Node_Procedure :: struct {
|
||||||
#as using n: Node;
|
#as using n: Node;
|
||||||
n.kind = .procedure;
|
n.kind = .procedure;
|
||||||
|
|
||||||
header: *Node_Procedure_Header;
|
arguments: [..]Parameter;
|
||||||
|
returns: [..]Parameter;
|
||||||
|
|
||||||
args: [..]Node_Parameter;
|
symbol: *Node_Symbol; // can be null
|
||||||
rets: [..]Node_Parameter;
|
head: *Node_Type; // will always be of type .procedure
|
||||||
body: *Node_Block;
|
block: *Node_Block;
|
||||||
flags: Flag;
|
flags: Flag;
|
||||||
|
|
||||||
Flag :: enum_flags {
|
Flag :: enum_flags {
|
||||||
must_inline;
|
must_inline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node_Parameter :: struct {
|
Parameter :: struct {
|
||||||
symbol: *Node_Symbol;
|
symbol: *Node_Symbol;
|
||||||
type: *Node_Type;
|
type: *Node_Type;
|
||||||
value: *Node; // always an expression, can be null
|
value: *Node; // always an expression, can be null
|
||||||
}
|
}
|
||||||
|
|
||||||
Node_Procedure_Header :: struct {
|
|
||||||
args: [..]*Node_Type;
|
|
||||||
rets: [..]*Node_Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node_Print :: struct {
|
Node_Print :: struct {
|
||||||
#as using n: Node;
|
#as using n: Node;
|
||||||
n.kind = .print;
|
n.kind = .print;
|
||||||
|
|
@ -211,14 +212,15 @@ Node_Procedure_Call :: struct {
|
||||||
#as using n: Node;
|
#as using n: Node;
|
||||||
n.kind = .procedure_call;
|
n.kind = .procedure_call;
|
||||||
|
|
||||||
call_expr: *Node;
|
call_expr: *Node;
|
||||||
named_arguments: kv.Kv(*Node, *Node);
|
named_arguments: kv.Kv(*Node, *Node);
|
||||||
all_arguments: [..]*Node;
|
all_arguments: [..]*Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node_Block :: struct {
|
Node_Block :: struct {
|
||||||
#as using n: Node;
|
#as using n: Node;
|
||||||
n.kind = .block;
|
n.kind = .block;
|
||||||
|
|
||||||
body: [..]*Node;
|
body: [..]*Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -277,7 +279,7 @@ parse_toplevel :: (p: *Parser) -> *Node {
|
||||||
s:, ok = expect_token(p, .symbol);
|
s:, ok = expect_token(p, .symbol);
|
||||||
basic.assert(ok, "symbol"); // @errors
|
basic.assert(ok, "symbol"); // @errors
|
||||||
|
|
||||||
type_expr: *Node;
|
type_expr: *Node_Type;
|
||||||
value_expr: *Node;
|
value_expr: *Node;
|
||||||
is_const := t.kind == .kw_def;
|
is_const := t.kind == .kw_def;
|
||||||
|
|
||||||
|
|
@ -316,7 +318,6 @@ parse_toplevel :: (p: *Parser) -> *Node {
|
||||||
// return expr0, ..exprN
|
// return expr0, ..exprN
|
||||||
case .kw_return;
|
case .kw_return;
|
||||||
node := make_node(p, Node_Return);
|
node := make_node(p, Node_Return);
|
||||||
array.init(*node.values, p.allocator);
|
|
||||||
|
|
||||||
prev_offset := p.offset;
|
prev_offset := p.offset;
|
||||||
expr := parse_expression(p);
|
expr := parse_expression(p);
|
||||||
|
|
@ -338,7 +339,7 @@ parse_toplevel :: (p: *Parser) -> *Node {
|
||||||
node.expr = expr;
|
node.expr = expr;
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
// fn symbol(arg0, ..argN) do end
|
// fn symbol(arg0, ..argN) do ... end
|
||||||
case .kw_fn;
|
case .kw_fn;
|
||||||
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
|
||||||
|
|
@ -346,12 +347,20 @@ parse_toplevel :: (p: *Parser) -> *Node {
|
||||||
t, ok = expect_token(p, .l_paren);
|
t, ok = expect_token(p, .l_paren);
|
||||||
basic.assert(ok, "expected '(' but found '%'", t.str); // @errors
|
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) {
|
while !at_end(p) {
|
||||||
t = peek_token(p);
|
t = peek_token(p);
|
||||||
if t.kind == .r_paren break;
|
if t.kind == .r_paren break;
|
||||||
|
|
||||||
expr := parse_expression(p);
|
sym, ok := expect_token(p, .symbol);
|
||||||
basic.assert(expr != null); // @errors
|
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);
|
t = peek_token(p);
|
||||||
if t.kind == {
|
if t.kind == {
|
||||||
|
|
@ -368,12 +377,10 @@ parse_toplevel :: (p: *Parser) -> *Node {
|
||||||
_, ok = expect_token(p, .r_paren);
|
_, ok = expect_token(p, .r_paren);
|
||||||
basic.assert(ok, "expected ')'"); // @errors
|
basic.assert(ok, "expected ')'"); // @errors
|
||||||
|
|
||||||
block := parse_block(p);
|
node.block = parse_block(p);
|
||||||
basic.assert(block != null, "expected block"); // @errors
|
basic.assert(node.block != null, "expected block"); // @errors
|
||||||
|
|
||||||
node := make_node(p, Node_Procedure);
|
return node;
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -384,7 +391,6 @@ parse_block :: (p: *Parser) -> *Node_Block {
|
||||||
basic.assert(ok, "expected 'do' found '%'", t.str); // @errors
|
basic.assert(ok, "expected 'do' found '%'", t.str); // @errors
|
||||||
|
|
||||||
block := make_node(p, Node_Block);
|
block := make_node(p, Node_Block);
|
||||||
array.init(*block.body, p.allocator);
|
|
||||||
|
|
||||||
while !at_end(p) {
|
while !at_end(p) {
|
||||||
t = peek_token(p);
|
t = peek_token(p);
|
||||||
|
|
@ -411,14 +417,12 @@ parse_type_expression :: (p: *Parser) -> *Node_Type {
|
||||||
target := parse_type_expression(p);
|
target := parse_type_expression(p);
|
||||||
basic.assert(target != null, "pointer target"); // @errors
|
basic.assert(target != null, "pointer target"); // @errors
|
||||||
|
|
||||||
node := make_node(p, Node_Type);
|
node := make_node(p, .pointer);
|
||||||
node.type_kind = .pointer;
|
|
||||||
node.pointer_target = target;
|
node.pointer_target = target;
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
case .l_square;
|
case .l_square;
|
||||||
node := make_node(p, Node_Type);
|
node := make_node(p, .array);
|
||||||
node.type_kind = .array;
|
|
||||||
|
|
||||||
// slice
|
// slice
|
||||||
if peek_token(p).kind == .r_square {
|
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 := make_node(p, Node_Symbol);
|
||||||
symbol.str = t.str;
|
symbol.str = t.str;
|
||||||
|
|
||||||
node := make_node(p, Node_Type);
|
node := make_node(p, .named);
|
||||||
node.type_kind = .alias;
|
node.name_target = symbol;
|
||||||
node.alias_target = symbol;
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -540,9 +543,6 @@ parse_expression_postfix :: (p: *Parser) -> *Node {
|
||||||
node := make_node(p, Node_Procedure_Call);
|
node := make_node(p, Node_Procedure_Call);
|
||||||
node.call_expr = base;
|
node.call_expr = base;
|
||||||
|
|
||||||
array.init(*node.all_arguments, p.allocator);
|
|
||||||
kv.init(*node.named_arguments, p.allocator);
|
|
||||||
|
|
||||||
while !at_end(p) {
|
while !at_end(p) {
|
||||||
t = peek_token(p);
|
t = peek_token(p);
|
||||||
if t.kind == .r_paren break;
|
if t.kind == .r_paren break;
|
||||||
|
|
@ -641,7 +641,35 @@ parse_expression_base :: (p: *Parser) -> *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
make_node :: (p: *Parser, $T: Type) -> *T {
|
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 {
|
peek_token :: (p: *Parser) -> Token {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue