Compare commits
No commits in common. "5038517d72c2b3bed9e6224bea66bbb14230ee77" and "1d82f6f5499ebb66bae73cbd9185bc83f805ea38" have entirely different histories.
5038517d72
...
1d82f6f549
3 changed files with 37 additions and 201 deletions
|
|
@ -63,7 +63,7 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
|
||||||
|
|
||||||
value := value_nil;
|
value := value_nil;
|
||||||
if var.value_expr != null {
|
if var.value_expr != null {
|
||||||
value = interp_expression(i, var.value_expr, scope);
|
value = interp_expr(i, var.value_expr, scope);
|
||||||
basic.assert(value != null); // @errors
|
basic.assert(value != null); // @errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
|
||||||
case .assign;
|
case .assign;
|
||||||
assign := stmt.(*Node_Assign);
|
assign := stmt.(*Node_Assign);
|
||||||
|
|
||||||
src := interp_expression(i, assign.src, scope);
|
src := interp_expr(i, assign.src, scope);
|
||||||
basic.assert(src != null); // @errors
|
basic.assert(src != null); // @errors
|
||||||
|
|
||||||
dst := interp_lvalue(i, assign.dst, scope);
|
dst := interp_lvalue(i, assign.dst, scope);
|
||||||
|
|
@ -80,8 +80,10 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
|
||||||
basic.assert(dst.kind == .value); // @errors
|
basic.assert(dst.kind == .value); // @errors
|
||||||
|
|
||||||
// @todo: typechecking
|
// @todo: typechecking
|
||||||
basic.assert(assign.op.kind == .equal, "unexpected assign op: %", assign.op.kind);
|
if assign.op.kind == {
|
||||||
dst.val.* = src.*;
|
case .equal;
|
||||||
|
dst.val.* = src.*;
|
||||||
|
}
|
||||||
|
|
||||||
case .procedure;
|
case .procedure;
|
||||||
proc := stmt.(*Node_Procedure);
|
proc := stmt.(*Node_Procedure);
|
||||||
|
|
@ -94,7 +96,7 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
|
||||||
|
|
||||||
case .print;
|
case .print;
|
||||||
print := stmt.(*Node_Print);
|
print := stmt.(*Node_Print);
|
||||||
expr := interp_expression(i, print.expr, scope);
|
expr := interp_expr(i, print.expr, scope);
|
||||||
if expr == null return;
|
if expr == null return;
|
||||||
|
|
||||||
if expr.kind == {
|
if expr.kind == {
|
||||||
|
|
@ -109,15 +111,8 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
|
||||||
|
|
||||||
basic.print("\n");
|
basic.print("\n");
|
||||||
|
|
||||||
case .assert;
|
|
||||||
assert := stmt.(*Node_Assert);
|
|
||||||
expr := interp_expression(i, assert.expr, scope);
|
|
||||||
basic.assert(expr != null, "runtime assertion failed");
|
|
||||||
basic.assert(expr.kind == .bool, "non-boolean expression given to assert");
|
|
||||||
basic.assert(expr.b, "runtime assertion failed");
|
|
||||||
|
|
||||||
case;
|
case;
|
||||||
interp_expression(i, stmt, scope);
|
interp_expr(i, stmt, scope);
|
||||||
// basic.assert(false, "unhandled node kind: %", stmt.kind); // @errors
|
// basic.assert(false, "unhandled node kind: %", stmt.kind); // @errors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +133,7 @@ interp_lvalue :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Valu
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interp_expression :: (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;
|
||||||
call := expr.(*Node_Procedure_Call);
|
call := expr.(*Node_Procedure_Call);
|
||||||
|
|
@ -158,14 +153,14 @@ interp_expression :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_
|
||||||
|
|
||||||
proc_scope := make_scope(scope);
|
proc_scope := make_scope(scope);
|
||||||
for proc.arguments {
|
for proc.arguments {
|
||||||
kv.set(*proc_scope.bindings, it.symbol.str, interp_expression(i, args[it_index], scope));
|
kv.set(*proc_scope.bindings, it.symbol.str, interp_expr(i, args[it_index], scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
for expr: proc.block.body {
|
for expr: proc.block.body {
|
||||||
if expr.kind == .return_ {
|
if expr.kind == .return_ {
|
||||||
ret := expr.(*Node_Return);
|
ret := expr.(*Node_Return);
|
||||||
if ret.values.count != 0 {
|
if ret.values.count != 0 {
|
||||||
result = interp_expression(i, ret.values[0], proc_scope);
|
result = interp_expr(i, ret.values[0], proc_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -192,7 +187,7 @@ interp_expression :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_
|
||||||
}
|
}
|
||||||
|
|
||||||
un := expr.(*Node_Unary);
|
un := expr.(*Node_Unary);
|
||||||
rhs := interp_expression(i, un.right, scope);
|
rhs := interp_expr(i, un.right, scope);
|
||||||
res := make_interp_value(i, rhs.kind);
|
res := make_interp_value(i, rhs.kind);
|
||||||
if un.op.kind == {
|
if un.op.kind == {
|
||||||
case .plus; do_unop(#code ifx right < 0 then -right else right);
|
case .plus; do_unop(#code ifx right < 0 then -right else right);
|
||||||
|
|
@ -204,8 +199,8 @@ interp_expression :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_
|
||||||
|
|
||||||
case .binary;
|
case .binary;
|
||||||
bin := expr.(*Node_Binary);
|
bin := expr.(*Node_Binary);
|
||||||
lhs := interp_expression(i, bin.left, scope);
|
lhs := interp_expr(i, bin.left, scope);
|
||||||
rhs := interp_expression(i, bin.right, scope);
|
rhs := interp_expr(i, bin.right, scope);
|
||||||
basic.assert(lhs.kind == rhs.kind, "type mismatch % vs. %", lhs.kind, rhs.kind); // @errors
|
basic.assert(lhs.kind == rhs.kind, "type mismatch % vs. %", lhs.kind, rhs.kind); // @errors
|
||||||
|
|
||||||
do_binop :: (code: Code) #expand {
|
do_binop :: (code: Code) #expand {
|
||||||
|
|
@ -225,38 +220,16 @@ interp_expression :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_
|
||||||
|
|
||||||
res := make_interp_value(i, lhs.kind);
|
res := make_interp_value(i, lhs.kind);
|
||||||
if bin.op.kind == {
|
if bin.op.kind == {
|
||||||
case .plus; do_binop(#code left + right);
|
case .plus; do_binop(#code left + right);
|
||||||
case .minus; do_binop(#code left - right);
|
case .minus; do_binop(#code left - right);
|
||||||
case .star; do_binop(#code left * right);
|
case .star; do_binop(#code left * right);
|
||||||
|
|
||||||
case .f_slash;
|
case .f_slash;
|
||||||
basic.assert(rhs.i != 0, "divide by zero"); // @errors
|
basic.assert(rhs.i != 0, "divide by zero"); // @errors
|
||||||
do_binop(#code left / right);
|
do_binop(#code left / right);
|
||||||
|
|
||||||
case .percent;
|
case .percent;
|
||||||
basic.assert(lhs.kind == .int, "cannot use binary operator '%%' on values of type '%'", lhs.kind);
|
basic.assert(lhs.kind == .int, "cannot use binary operator '%%' on values of type '%'", lhs.kind);
|
||||||
res.i = lhs.i % rhs.i;
|
res.i = lhs.i % rhs.i;
|
||||||
|
|
||||||
// @todo: typechecking
|
|
||||||
case .equal_equal;
|
|
||||||
res.kind = .bool;
|
|
||||||
res.b = lhs.i == rhs.i;
|
|
||||||
case .bang_equal;
|
|
||||||
res.kind = .bool;
|
|
||||||
res.b = lhs.i != rhs.i;
|
|
||||||
case .less;
|
|
||||||
res.kind = .bool;
|
|
||||||
res.b = lhs.i < rhs.i;
|
|
||||||
case .less_equal;
|
|
||||||
res.kind = .bool;
|
|
||||||
res.b = lhs.i <= rhs.i;
|
|
||||||
case .more;
|
|
||||||
res.kind = .bool;
|
|
||||||
res.b = lhs.i > rhs.i;
|
|
||||||
case .more_equal;
|
|
||||||
res.kind = .bool;
|
|
||||||
res.b = lhs.i >= rhs.i;
|
|
||||||
|
|
||||||
case; basic.assert(false, "unhandled binary operator '%'", bin.op.str);
|
case; basic.assert(false, "unhandled binary operator '%'", bin.op.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ strings :: #import "String"; // @future
|
||||||
|
|
||||||
var x = 21.0
|
var x = 21.0
|
||||||
var y = 22.0
|
var y = 22.0
|
||||||
var z = x + y
|
|
||||||
|
|
||||||
x = x + 1.0 / 2.0
|
x = x + 1.0 / 2.0
|
||||||
print x
|
print x
|
||||||
|
|
@ -36,53 +35,7 @@ strings :: #import "String"; // @future
|
||||||
x = add(x, div(1.0, 2.0))
|
x = add(x, div(1.0, 2.0))
|
||||||
print x
|
print x
|
||||||
|
|
||||||
print x == x
|
print add(x, y)
|
||||||
print x == y
|
|
||||||
print x == z
|
|
||||||
|
|
||||||
assert x == y
|
|
||||||
assert x != z
|
|
||||||
|
|
||||||
// def (
|
|
||||||
// Add = poly[T] proc(x T, y T) T do return x + y end
|
|
||||||
// Sub = poly[T] proc(x T, y T) T do return x - y end
|
|
||||||
// Mul = poly[T] proc(x T, y T) T do return x * y end
|
|
||||||
// Div = poly[T] proc(x T, y T) T do return x / y end
|
|
||||||
// )
|
|
||||||
|
|
||||||
// def (
|
|
||||||
// Addi = Add[int]
|
|
||||||
// Addf = Add[float]
|
|
||||||
// Subi = Sub[int]
|
|
||||||
// Subf = Sub[float]
|
|
||||||
// Muli = Mul[int]
|
|
||||||
// Mulf = Mul[float]
|
|
||||||
// Divi = Div[int]
|
|
||||||
// Divf = Div[float]
|
|
||||||
// )
|
|
||||||
|
|
||||||
// def Foo = struct {
|
|
||||||
// x int = 1
|
|
||||||
// y int = 2
|
|
||||||
// z int = 3
|
|
||||||
// }
|
|
||||||
|
|
||||||
// def Value = union {
|
|
||||||
// i int
|
|
||||||
// f float
|
|
||||||
// b bool
|
|
||||||
// }
|
|
||||||
|
|
||||||
// def Kind = enum {
|
|
||||||
// a
|
|
||||||
// b
|
|
||||||
// c
|
|
||||||
// d
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var foo = Foo{ x = 10, y = 20, z = 30 }
|
|
||||||
// var val = Value{ f = 3.14 }
|
|
||||||
// var kind = Kind.a
|
|
||||||
END);
|
END);
|
||||||
|
|
||||||
interp: Interp;
|
interp: Interp;
|
||||||
|
|
|
||||||
128
vm/parser.jai
128
vm/parser.jai
|
|
@ -31,23 +31,6 @@ Token :: struct {
|
||||||
kw_false;
|
kw_false;
|
||||||
|
|
||||||
kw_print;
|
kw_print;
|
||||||
kw_assert;
|
|
||||||
|
|
||||||
equal_equal; // ==
|
|
||||||
bang_equal; // !=
|
|
||||||
and_equal; // &=
|
|
||||||
or_equal; // |=
|
|
||||||
less_equal; // <=
|
|
||||||
more_equal; // >=
|
|
||||||
|
|
||||||
plus_equal; // +=
|
|
||||||
minus_equal; // -=
|
|
||||||
star_equal; // *=
|
|
||||||
f_slash_equal; // /=
|
|
||||||
percent_equal; // %=
|
|
||||||
|
|
||||||
and_and_equal; // &&=
|
|
||||||
or_or_equal; // ||=
|
|
||||||
|
|
||||||
equal :: #char "=";
|
equal :: #char "=";
|
||||||
plus :: #char "+";
|
plus :: #char "+";
|
||||||
|
|
@ -56,11 +39,8 @@ Token :: struct {
|
||||||
percent :: #char "%";
|
percent :: #char "%";
|
||||||
bang :: #char "!";
|
bang :: #char "!";
|
||||||
and :: #char "&";
|
and :: #char "&";
|
||||||
or :: #char "|";
|
|
||||||
f_slash :: #char "/";
|
f_slash :: #char "/";
|
||||||
b_slash :: #char "\\";
|
b_slash :: #char "\\";
|
||||||
less :: #char "<";
|
|
||||||
more :: #char ">";
|
|
||||||
|
|
||||||
l_paren :: #char "(";
|
l_paren :: #char "(";
|
||||||
r_paren :: #char ")";
|
r_paren :: #char ")";
|
||||||
|
|
@ -72,7 +52,6 @@ Token :: struct {
|
||||||
dot :: #char ".";
|
dot :: #char ".";
|
||||||
colon :: #char ":";
|
colon :: #char ":";
|
||||||
semicolon :: #char ";";
|
semicolon :: #char ";";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +66,6 @@ Node :: struct {
|
||||||
|
|
||||||
stmt_start;
|
stmt_start;
|
||||||
print;
|
print;
|
||||||
assert;
|
|
||||||
return_;
|
return_;
|
||||||
assign;
|
assign;
|
||||||
stmt_end;
|
stmt_end;
|
||||||
|
|
@ -240,13 +218,6 @@ Node_Print :: struct {
|
||||||
expr: *Node;
|
expr: *Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node_Assert :: struct {
|
|
||||||
#as using n: Node;
|
|
||||||
n.kind = .assert;
|
|
||||||
|
|
||||||
expr: *Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node_Procedure_Call :: struct {
|
Node_Procedure_Call :: struct {
|
||||||
#as using n: Node;
|
#as using n: Node;
|
||||||
n.kind = .procedure_call;
|
n.kind = .procedure_call;
|
||||||
|
|
@ -382,18 +353,6 @@ parse_statement :: (p: *Parser) -> *Node {
|
||||||
node.expr = expr;
|
node.expr = expr;
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
// assert(cond)
|
|
||||||
// assert cond
|
|
||||||
case .kw_assert;
|
|
||||||
consume_token(p);
|
|
||||||
|
|
||||||
expr := parse_expression(p);
|
|
||||||
basic.assert(expr != null, "expected expression"); // @errors
|
|
||||||
|
|
||||||
node := make_node(p, Node_Assert);
|
|
||||||
node.expr = expr;
|
|
||||||
return node;
|
|
||||||
|
|
||||||
// fn symbol(arg0, ..argN) do ... end
|
// fn symbol(arg0, ..argN) do ... end
|
||||||
case .kw_fn;
|
case .kw_fn;
|
||||||
consume_token(p);
|
consume_token(p);
|
||||||
|
|
@ -453,12 +412,7 @@ parse_simple_statement :: (p: *Parser) -> *Node {
|
||||||
|
|
||||||
t := peek_token(p);
|
t := peek_token(p);
|
||||||
if t.kind == {
|
if t.kind == {
|
||||||
case .equal; #through;
|
case .equal;
|
||||||
case .plus_equal; #through;
|
|
||||||
case .minus_equal; #through;
|
|
||||||
case .star_equal; #through;
|
|
||||||
case .f_slash_equal; #through;
|
|
||||||
case .percent_equal;
|
|
||||||
consume_token(p);
|
consume_token(p);
|
||||||
|
|
||||||
src := parse_expression(p);
|
src := parse_expression(p);
|
||||||
|
|
@ -467,29 +421,7 @@ parse_simple_statement :: (p: *Parser) -> *Node {
|
||||||
node := make_node(p, Node_Assign);
|
node := make_node(p, Node_Assign);
|
||||||
node.op = t;
|
node.op = t;
|
||||||
node.dst = dst;
|
node.dst = dst;
|
||||||
|
node.src = src;
|
||||||
if t.kind == .equal {
|
|
||||||
node.src = src;
|
|
||||||
}
|
|
||||||
// transform these into 'dst = dst op src'
|
|
||||||
else {
|
|
||||||
bin := make_node(p, Node_Binary);
|
|
||||||
bin.left = dst;
|
|
||||||
bin.right = src;
|
|
||||||
bin.op = t;
|
|
||||||
|
|
||||||
if t.kind == {
|
|
||||||
case .plus_equal; bin.op.kind = .plus;
|
|
||||||
case .minus_equal; bin.op.kind = .minus;
|
|
||||||
case .star_equal; bin.op.kind = .star;
|
|
||||||
case .f_slash_equal; bin.op.kind = .f_slash;
|
|
||||||
case .percent_equal; bin.op.kind = .percent;
|
|
||||||
}
|
|
||||||
|
|
||||||
node.op.kind = .equal;
|
|
||||||
node.src = bin;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,13 +516,13 @@ parse_expression :: (p: *Parser, min_precedence := 1) -> *Node {
|
||||||
case .minus;
|
case .minus;
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
case .equal_equal; #through;
|
// case .equal_equal; #through;
|
||||||
case .bang_equal; #through;
|
// case .bang_equal; #through;
|
||||||
case .less; #through;
|
// case .less; #through;
|
||||||
case .less_equal; #through;
|
// case .less_equal; #through;
|
||||||
case .more; #through;
|
// case .more; #through;
|
||||||
case .more_equal;
|
// case .more_equal;
|
||||||
return 2;
|
// return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -870,9 +802,8 @@ consume_token :: (p: *Parser) -> Token {
|
||||||
case "true"; t.kind = .kw_true;
|
case "true"; t.kind = .kw_true;
|
||||||
case "false"; t.kind = .kw_false;
|
case "false"; t.kind = .kw_false;
|
||||||
|
|
||||||
case "print"; t.kind = .kw_print;
|
case "print"; t.kind = .kw_print;
|
||||||
case "assert"; t.kind = .kw_assert;
|
case; t.kind = .symbol;
|
||||||
case; t.kind = .symbol;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
|
|
@ -890,36 +821,15 @@ consume_token :: (p: *Parser) -> Token {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
with_optional_equal :: (current_kind: Token.Kind, equal_kind: Token.Kind) -> Token #expand {
|
|
||||||
token := Token.{
|
|
||||||
kind = current_kind,
|
|
||||||
str = string.{ data = `p.source.data + `p.offset, count = 1 },
|
|
||||||
};
|
|
||||||
|
|
||||||
`p.offset += 1;
|
|
||||||
if `p.offset < `p.source.count && `p.source[`p.offset] == #char "=" {
|
|
||||||
`p.offset += 1;
|
|
||||||
|
|
||||||
token.kind = equal_kind;
|
|
||||||
token.str.count = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
if c == {
|
if c == {
|
||||||
case "+"; return with_optional_equal(c.(Token.Kind), .plus_equal);
|
case "+"; #through;
|
||||||
case "-"; return with_optional_equal(c.(Token.Kind), .minus_equal);
|
case "-"; #through;
|
||||||
case "*"; return with_optional_equal(c.(Token.Kind), .star_equal);
|
case "*"; #through;
|
||||||
case "/"; return with_optional_equal(c.(Token.Kind), .f_slash_equal);
|
case "/"; #through;
|
||||||
case "="; return with_optional_equal(c.(Token.Kind), .equal_equal);
|
case "="; #through;
|
||||||
case "%"; return with_optional_equal(c.(Token.Kind), .percent_equal);
|
case "%"; #through;
|
||||||
case "!"; return with_optional_equal(c.(Token.Kind), .bang_equal);
|
case "!"; #through;
|
||||||
case "&"; return with_optional_equal(c.(Token.Kind), .and_equal);
|
case "&"; #through;
|
||||||
case "|"; return with_optional_equal(c.(Token.Kind), .or_equal);
|
|
||||||
case "<"; return with_optional_equal(c.(Token.Kind), .less_equal);
|
|
||||||
case ">"; return with_optional_equal(c.(Token.Kind), .more_equal);
|
|
||||||
|
|
||||||
case ","; #through;
|
case ","; #through;
|
||||||
case "."; #through;
|
case "."; #through;
|
||||||
case ":"; #through;
|
case ":"; #through;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue