[vm] return statements and start of procedure parsing

This commit is contained in:
Judah Caruso 2025-06-03 21:43:11 -06:00
parent dc04c0463b
commit 08769c7a6d
2 changed files with 131 additions and 4 deletions

View file

@ -21,6 +21,9 @@ strings :: #import "String"; // @future
init(*parser, context.allocator);
ok := parse_string(*parser, #string END
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 z = x + y * 2.0 / 3.0

View file

@ -13,6 +13,7 @@ Token :: struct {
kw_var;
kw_def;
kw_type;
kw_fn;
kw_do;
kw_end;
kw_if;
@ -61,12 +62,16 @@ Node :: struct {
Kind :: enum {
invalid;
block;
stmt_start;
print;
return_;
stmt_end;
decl_start;
variable;
procedure;
decl_end;
expr_start;
@ -184,6 +189,50 @@ Node_Type :: struct {
}
}
/*
fn add(x int, y int) int do return x + y end
*/
Node_Procedure :: struct {
#as using n: Node;
n.kind = .procedure;
header: *Node_Procedure_Header;
args: [..]Node_Argument;
rets: [..]Node_Argument;
body: *Node_Block;
flags: Flag;
Flag :: enum_flags {
inline_;
}
}
Node_Argument :: 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_Block :: struct {
#as using n: Node;
n.kind = .block;
body: [..]*Node;
}
Node_Return :: struct {
#as using n: Node;
n.kind = .return_;
values: [..]*Node;
}
Parser :: struct {
allocator: Allocator;
toplevel: [..]*Node;
@ -210,9 +259,7 @@ parse_string :: (p: *Parser, source: string) -> bool {
}
node := parse_toplevel(p);
if node == null break;
array.append(*p.toplevel, node);
if node != null array.append(*p.toplevel, node);
}
return false;
@ -222,7 +269,7 @@ parse_string :: (p: *Parser, source: string) -> bool {
#scope_file;
parse_toplevel :: (p: *Parser) -> *Node {
t, ok := expect_token(p, .kw_var, .kw_def, .kw_print);
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
if t.kind == {
@ -269,6 +316,22 @@ parse_toplevel :: (p: *Parser) -> *Node {
return node;
// return
// 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);
if expr == null {
p.offset = prev_offset;
return node;
}
array.append(*node.values, expr);
return node;
// print(expr)
// print expr
case .kw_print;
@ -278,11 +341,71 @@ parse_toplevel :: (p: *Parser) -> *Node {
node := make_node(p, Node_Print);
node.expr = expr;
return node;
// 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
t, ok = expect_token(p, .l_paren);
basic.assert(ok, "expected '(' but found '%'", t.str); // @errors
while !at_end(p) {
t = peek_token(p);
if t.kind == .r_paren break;
expr := parse_expression(p);
basic.assert(expr != null); // @errors
t = peek_token(p);
if t.kind == {
case .comma;
consume_token(p);
continue;
case .r_paren;
break;
case;
basic.assert(false, "expected ',' or ')' but found '%'", t.str);
}
}
_, ok = expect_token(p, .r_paren);
basic.assert(ok, "expected ')'"); // @errors
block := parse_block(p);
basic.assert(block != null, "expected block"); // @errors
node := make_node(p, Node_Procedure);
return null;
}
return null;
}
parse_block :: (p: *Parser) -> *Node_Block {
t, ok := expect_token(p, .kw_do);
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);
if t.kind == .kw_end break;
node := parse_toplevel(p);
basic.assert(node != null); // @errors
array.append(*block.body, node);
}
t, ok = expect_token(p, .kw_end);
basic.assert(ok, "expected 'end' found '%'", t.str); // @errors
return block;
}
parse_type_expression :: (p: *Parser) -> *Node_Type {
t, ok := expect_token(p, .symbol, .star, .l_square);
basic.assert(ok, "type expression"); // @errors
@ -596,6 +719,7 @@ consume_token :: (p: *Parser) -> Token {
case "var"; t.kind = .kw_var;
case "def"; t.kind = .kw_def;
case "type"; t.kind = .kw_type;
case "fn"; t.kind = .kw_fn;
case "do"; t.kind = .kw_do;
case "end"; t.kind = .kw_end;
case "if"; t.kind = .kw_if;