improvements
This commit is contained in:
parent
3bfa0679ae
commit
3f81359ab1
3 changed files with 105 additions and 21 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue