Compare commits

..

No commits in common. "5038517d72c2b3bed9e6224bea66bbb14230ee77" and "1d82f6f5499ebb66bae73cbd9185bc83f805ea38" have entirely different histories.

3 changed files with 37 additions and 201 deletions

View file

@ -63,7 +63,7 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
value := value_nil;
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
}
@ -72,7 +72,7 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
case .assign;
assign := stmt.(*Node_Assign);
src := interp_expression(i, assign.src, scope);
src := interp_expr(i, assign.src, scope);
basic.assert(src != null); // @errors
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
// @todo: typechecking
basic.assert(assign.op.kind == .equal, "unexpected assign op: %", assign.op.kind);
dst.val.* = src.*;
if assign.op.kind == {
case .equal;
dst.val.* = src.*;
}
case .procedure;
proc := stmt.(*Node_Procedure);
@ -94,7 +96,7 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
case .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.kind == {
@ -109,15 +111,8 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
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;
interp_expression(i, stmt, scope);
interp_expr(i, stmt, scope);
// 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;
}
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 == {
case .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);
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 {
if expr.kind == .return_ {
ret := expr.(*Node_Return);
if ret.values.count != 0 {
result = interp_expression(i, ret.values[0], proc_scope);
result = interp_expr(i, ret.values[0], proc_scope);
}
break;
@ -192,7 +187,7 @@ interp_expression :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_
}
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);
if un.op.kind == {
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;
bin := expr.(*Node_Binary);
lhs := interp_expression(i, bin.left, scope);
rhs := interp_expression(i, bin.right, scope);
lhs := interp_expr(i, bin.left, scope);
rhs := interp_expr(i, bin.right, scope);
basic.assert(lhs.kind == rhs.kind, "type mismatch % vs. %", lhs.kind, rhs.kind); // @errors
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);
if bin.op.kind == {
case .plus; do_binop(#code left + right);
case .minus; do_binop(#code left - right);
case .star; do_binop(#code left * right);
case .plus; do_binop(#code left + right);
case .minus; do_binop(#code left - right);
case .star; do_binop(#code left * right);
case .f_slash;
basic.assert(rhs.i != 0, "divide by zero"); // @errors
do_binop(#code left / right);
case .percent;
basic.assert(lhs.kind == .int, "cannot use binary operator '%%' on values of type '%'", lhs.kind);
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);
}

View file

@ -28,7 +28,6 @@ strings :: #import "String"; // @future
var x = 21.0
var y = 22.0
var z = x + y
x = x + 1.0 / 2.0
print x
@ -36,53 +35,7 @@ strings :: #import "String"; // @future
x = add(x, div(1.0, 2.0))
print x
print x == x
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
print add(x, y)
END);
interp: Interp;

View file

@ -31,23 +31,6 @@ Token :: struct {
kw_false;
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 "=";
plus :: #char "+";
@ -56,11 +39,8 @@ Token :: struct {
percent :: #char "%";
bang :: #char "!";
and :: #char "&";
or :: #char "|";
f_slash :: #char "/";
b_slash :: #char "\\";
less :: #char "<";
more :: #char ">";
l_paren :: #char "(";
r_paren :: #char ")";
@ -72,7 +52,6 @@ Token :: struct {
dot :: #char ".";
colon :: #char ":";
semicolon :: #char ";";
}
}
@ -87,7 +66,6 @@ Node :: struct {
stmt_start;
print;
assert;
return_;
assign;
stmt_end;
@ -240,13 +218,6 @@ Node_Print :: struct {
expr: *Node;
}
Node_Assert :: struct {
#as using n: Node;
n.kind = .assert;
expr: *Node;
}
Node_Procedure_Call :: struct {
#as using n: Node;
n.kind = .procedure_call;
@ -382,18 +353,6 @@ parse_statement :: (p: *Parser) -> *Node {
node.expr = expr;
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
case .kw_fn;
consume_token(p);
@ -453,12 +412,7 @@ parse_simple_statement :: (p: *Parser) -> *Node {
t := peek_token(p);
if t.kind == {
case .equal; #through;
case .plus_equal; #through;
case .minus_equal; #through;
case .star_equal; #through;
case .f_slash_equal; #through;
case .percent_equal;
case .equal;
consume_token(p);
src := parse_expression(p);
@ -467,29 +421,7 @@ parse_simple_statement :: (p: *Parser) -> *Node {
node := make_node(p, Node_Assign);
node.op = t;
node.dst = dst;
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;
}
node.src = src;
return node;
}
@ -584,13 +516,13 @@ parse_expression :: (p: *Parser, min_precedence := 1) -> *Node {
case .minus;
return 3;
case .equal_equal; #through;
case .bang_equal; #through;
case .less; #through;
case .less_equal; #through;
case .more; #through;
case .more_equal;
return 2;
// case .equal_equal; #through;
// case .bang_equal; #through;
// case .less; #through;
// case .less_equal; #through;
// case .more; #through;
// case .more_equal;
// return 2;
}
return 0;
@ -870,9 +802,8 @@ consume_token :: (p: *Parser) -> Token {
case "true"; t.kind = .kw_true;
case "false"; t.kind = .kw_false;
case "print"; t.kind = .kw_print;
case "assert"; t.kind = .kw_assert;
case; t.kind = .symbol;
case "print"; t.kind = .kw_print;
case; t.kind = .symbol;
}
return t;
@ -890,36 +821,15 @@ consume_token :: (p: *Parser) -> Token {
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 == {
case "+"; return with_optional_equal(c.(Token.Kind), .plus_equal);
case "-"; return with_optional_equal(c.(Token.Kind), .minus_equal);
case "*"; return with_optional_equal(c.(Token.Kind), .star_equal);
case "/"; return with_optional_equal(c.(Token.Kind), .f_slash_equal);
case "="; return with_optional_equal(c.(Token.Kind), .equal_equal);
case "%"; return with_optional_equal(c.(Token.Kind), .percent_equal);
case "!"; return with_optional_equal(c.(Token.Kind), .bang_equal);
case "&"; return with_optional_equal(c.(Token.Kind), .and_equal);
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;
case "!"; #through;
case "&"; #through;
case ","; #through;
case "."; #through;
case ":"; #through;