move vm to x
This commit is contained in:
parent
90590b964a
commit
3adbcab494
5 changed files with 259 additions and 151 deletions
|
|
@ -1,94 +0,0 @@
|
|||
// #module_parameters(RUN_TESTS := false);
|
||||
|
||||
#load "parser.jai";
|
||||
#load "interp.jai";
|
||||
|
||||
#scope_module;
|
||||
|
||||
// exported to the entire module since we want these everywhere
|
||||
|
||||
mem :: #import "jc/memory";
|
||||
array :: #import "jc/array";
|
||||
kv :: #import "jc/kv";
|
||||
|
||||
basic :: #import "Basic"; // @future
|
||||
strings :: #import "String"; // @future
|
||||
|
||||
#scope_file;
|
||||
|
||||
#run {
|
||||
parser: Parser;
|
||||
ok := parse_string(*parser, #string END
|
||||
fn add(l, r) do return l + r end
|
||||
fn sub(l, r) do return l - r end
|
||||
fn mul(l, r) do return l * r end
|
||||
fn div(l, r) do return l / r end
|
||||
|
||||
var x = 21.0
|
||||
var y = 22.0
|
||||
var z = x + y
|
||||
|
||||
x = x + 1.0 / 2.0
|
||||
print x
|
||||
|
||||
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
|
||||
END);
|
||||
|
||||
interp: Interp;
|
||||
interp.toplevel = parser.toplevel;
|
||||
|
||||
interp_program(*interp);
|
||||
}
|
||||
|
||||
// #if RUN_TESTS {
|
||||
// test :: #import "jc/test";
|
||||
// }
|
||||
|
|
@ -1,10 +1,3 @@
|
|||
Interp :: struct {
|
||||
allocator: Allocator;
|
||||
|
||||
toplevel: []*Node;
|
||||
global: *Interp_Scope;
|
||||
}
|
||||
|
||||
Interp_Scope :: struct {
|
||||
parent: *Interp_Scope;
|
||||
bindings: kv.Kv(string, *Interp_Value);
|
||||
|
|
@ -36,7 +29,7 @@ Interp_Value :: struct {
|
|||
}
|
||||
}
|
||||
|
||||
interp_program :: (i: *Interp) {
|
||||
interp_program :: (i: *Vm) {
|
||||
try_lazy_init(i);
|
||||
|
||||
for i.toplevel {
|
||||
|
|
@ -44,7 +37,7 @@ interp_program :: (i: *Interp) {
|
|||
}
|
||||
}
|
||||
|
||||
interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
|
||||
interp_statement :: (i: *Vm, stmt: *Node, scope: *Interp_Scope) {
|
||||
if stmt.kind == {
|
||||
case .variable;
|
||||
var := stmt.(*Node_Var);
|
||||
|
|
@ -112,7 +105,7 @@ interp_statement :: (i: *Interp, stmt: *Node, scope: *Interp_Scope) {
|
|||
}
|
||||
}
|
||||
|
||||
interp_lvalue :: (i: *Interp, expr: *Node, scope: *Interp_Scope) -> *Interp_Value {
|
||||
interp_lvalue :: (i: *Vm, expr: *Node, scope: *Interp_Scope) -> *Interp_Value {
|
||||
if expr.kind == {
|
||||
case .symbol;
|
||||
sym := expr.(*Node_Symbol);
|
||||
|
|
@ -128,7 +121,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_expression :: (i: *Vm, expr: *Node, scope: *Interp_Scope) -> *Interp_Value {
|
||||
if expr.kind == {
|
||||
case .procedure_call;
|
||||
call := expr.(*Node_Procedure_Call);
|
||||
|
|
@ -302,13 +295,13 @@ make_scope :: (parent: *Interp_Scope) -> *Interp_Scope {
|
|||
return scope;
|
||||
}
|
||||
|
||||
make_interp_value :: (i: *Interp, kind: Interp_Value.Kind) -> *Interp_Value {
|
||||
value := mem.request_memory(Interp_Value,, allocator = i.allocator);
|
||||
make_interp_value :: (i: *Vm, kind: Interp_Value.Kind) -> *Interp_Value {
|
||||
value := mem.request_memory(Interp_Value,, allocator = i.interp_allocator);
|
||||
value.kind = kind;
|
||||
return value;
|
||||
}
|
||||
|
||||
try_lazy_init :: (i: *Interp) {
|
||||
try_lazy_init :: (i: *Vm) {
|
||||
value_nil = make_interp_value(i, .nil);
|
||||
|
||||
value_true = make_interp_value(i, .bool);
|
||||
202
x/vm/module.jai
Normal file
202
x/vm/module.jai
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
// #module_parameters(RUN_TESTS := false);
|
||||
|
||||
Vm :: struct {
|
||||
reports: [..]Report;
|
||||
|
||||
parser_allocator: Allocator;
|
||||
toplevel: [..]*Node;
|
||||
previous: Token;
|
||||
filename: string = "(unnamed file)";
|
||||
source: string;
|
||||
offset: int;
|
||||
|
||||
interp_allocator: Allocator;
|
||||
global: *Interp_Scope;
|
||||
}
|
||||
|
||||
#load "parser.jai";
|
||||
#load "resolver.jai";
|
||||
#load "interp.jai";
|
||||
|
||||
#scope_module;
|
||||
|
||||
Report :: struct {
|
||||
message: string;
|
||||
offset: int = -1;
|
||||
error: bool;
|
||||
extras: Extra = .show_entire_line;
|
||||
|
||||
Extra :: enum_flags {
|
||||
hide_location;
|
||||
show_entire_line;
|
||||
}
|
||||
}
|
||||
|
||||
report :: (vm: *Vm, message := "", args: ..Any) -> *Report {
|
||||
r: *Report;
|
||||
|
||||
if vm.reports.count != 0 {
|
||||
last := *vm.reports[vm.reports.count - 1];
|
||||
if last.offset == vm.offset {
|
||||
r = last;
|
||||
}
|
||||
else {
|
||||
r = array.append(*vm.reports);
|
||||
}
|
||||
}
|
||||
else {
|
||||
r = array.append(*vm.reports);
|
||||
}
|
||||
|
||||
r.message = basic.tprint(message, ..args);
|
||||
r.offset = vm.offset;
|
||||
return r;
|
||||
}
|
||||
|
||||
an_error_was_reported :: (vm: Vm) -> bool {
|
||||
if vm.reports.count == 0 return false;
|
||||
|
||||
reported_error := false;
|
||||
for < vm.reports {
|
||||
if it.error reported_error = true;
|
||||
|
||||
line := -1;
|
||||
column := -1;
|
||||
|
||||
if !(it.extras & .hide_location) {
|
||||
for 0..vm.source.count - 1 {
|
||||
if vm.source[it] == "\n" {
|
||||
line += 1;
|
||||
column = 1;
|
||||
}
|
||||
else {
|
||||
column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
basic.print("%:%,% ", vm.filename, line, column);
|
||||
}
|
||||
|
||||
basic.print("%\n", it.message);
|
||||
|
||||
if it.extras & .show_entire_line {
|
||||
i := it.offset;
|
||||
start := i;
|
||||
while i >= 0 {
|
||||
if vm.source[i] == "\n" {
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
end := it.offset;
|
||||
|
||||
i = it.offset;
|
||||
while i < vm.source.count {
|
||||
if vm.source[i] == "\n" {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
line := string.{ data = vm.source.data + start, count = end - start };
|
||||
basic.print("\t%\n", strings.trim(line));
|
||||
}
|
||||
}
|
||||
|
||||
return reported_error;
|
||||
}
|
||||
|
||||
// exported to the entire module since we want these everywhere
|
||||
|
||||
mem :: #import "jc/memory";
|
||||
array :: #import "jc/array";
|
||||
kv :: #import "jc/kv";
|
||||
|
||||
basic :: #import "Basic"; // @future
|
||||
strings :: #import "String"; // @future
|
||||
|
||||
#scope_file;
|
||||
|
||||
#run {
|
||||
vm: Vm;
|
||||
|
||||
ok := parse_string(*vm, #string END
|
||||
fn add(l, r) do return l + r end
|
||||
fn sub(l, r) do return l - r end
|
||||
fn mul(l, r) do return l * r end
|
||||
fn div(l, r) do return l / r end
|
||||
|
||||
var x = 21.0
|
||||
var y = 22.0
|
||||
var z = x + y
|
||||
|
||||
x = x + 1.0 / 2.0
|
||||
print x
|
||||
|
||||
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
|
||||
END);
|
||||
|
||||
if an_error_was_reported(vm) return;
|
||||
|
||||
resolve_everything(*vm);
|
||||
// generate_bytecode(*vm);
|
||||
// interp_bytecode(*vm);
|
||||
}
|
||||
|
||||
// #if RUN_TESTS {
|
||||
// test :: #import "jc/test";
|
||||
// }
|
||||
|
|
@ -296,17 +296,7 @@ Node_Return :: struct {
|
|||
}
|
||||
}
|
||||
|
||||
Parser :: struct {
|
||||
allocator: Allocator;
|
||||
toplevel: [..]*Node;
|
||||
|
||||
previous: Token;
|
||||
filename: string;
|
||||
source: string;
|
||||
offset: int;
|
||||
}
|
||||
|
||||
parse_string :: (p: *Parser, source: string) -> bool {
|
||||
parse_string :: (p: *Vm, source: string) -> bool {
|
||||
try_lazy_init(p);
|
||||
|
||||
p.source = source;
|
||||
|
|
@ -319,7 +309,7 @@ parse_string :: (p: *Parser, source: string) -> bool {
|
|||
}
|
||||
|
||||
node := parse_statement(p);
|
||||
if node != null array.append(*p.toplevel, node);
|
||||
if node == null array.append(*p.toplevel, node);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -328,7 +318,7 @@ parse_string :: (p: *Parser, source: string) -> bool {
|
|||
|
||||
#scope_file;
|
||||
|
||||
parse_statement :: (p: *Parser) -> *Node {
|
||||
parse_statement :: (p: *Vm) -> *Node {
|
||||
t := peek_token(p);
|
||||
if t.kind == {
|
||||
// var sym type_expr
|
||||
|
|
@ -470,9 +460,10 @@ parse_statement :: (p: *Parser) -> *Node {
|
|||
return parse_simple_statement(p);
|
||||
}
|
||||
|
||||
parse_simple_statement :: (p: *Parser) -> *Node {
|
||||
parse_simple_statement :: (p: *Vm) -> *Node {
|
||||
dst := parse_expression(p);
|
||||
basic.assert(dst != null, "expected expression for simple statement");
|
||||
if dst == null return null;
|
||||
// basic.assert(dst != null, "expected expression for simple statement");
|
||||
|
||||
t := peek_token(p);
|
||||
if t.kind == {
|
||||
|
|
@ -519,7 +510,7 @@ parse_simple_statement :: (p: *Parser) -> *Node {
|
|||
return dst;
|
||||
}
|
||||
|
||||
parse_block :: (p: *Parser) -> *Node_Block {
|
||||
parse_block :: (p: *Vm) -> *Node_Block {
|
||||
t, ok := expect_token(p, .kw_do);
|
||||
basic.assert(ok, "expected 'do' found '%'", t.str); // @errors
|
||||
|
||||
|
|
@ -541,7 +532,7 @@ parse_block :: (p: *Parser) -> *Node_Block {
|
|||
return block;
|
||||
}
|
||||
|
||||
parse_type_expression :: (p: *Parser) -> *Node_Type {
|
||||
parse_type_expression :: (p: *Vm) -> *Node_Type {
|
||||
t, ok := expect_token(p, .symbol, .star, .l_square);
|
||||
basic.assert(ok, "type expression"); // @errors
|
||||
|
||||
|
|
@ -594,7 +585,7 @@ parse_type_expression :: (p: *Parser) -> *Node_Type {
|
|||
return null;
|
||||
}
|
||||
|
||||
parse_expression :: (p: *Parser, min_precedence := 1) -> *Node {
|
||||
parse_expression :: (p: *Vm, min_precedence := 1) -> *Node {
|
||||
get_precedence :: inline (t: Token) -> int {
|
||||
if t.kind == {
|
||||
case .star; #through;
|
||||
|
|
@ -620,7 +611,7 @@ parse_expression :: (p: *Parser, min_precedence := 1) -> *Node {
|
|||
}
|
||||
|
||||
node := parse_expression_unary(p);
|
||||
basic.assert(node != null, "expected expression"); // @errors
|
||||
if node == null return null;
|
||||
|
||||
while !at_end(p) {
|
||||
op := peek_token(p);
|
||||
|
|
@ -644,7 +635,7 @@ parse_expression :: (p: *Parser, min_precedence := 1) -> *Node {
|
|||
return node;
|
||||
}
|
||||
|
||||
parse_expression_unary :: (p: *Parser) -> *Node {
|
||||
parse_expression_unary :: (p: *Vm) -> *Node {
|
||||
op := peek_token(p);
|
||||
if op.kind == {
|
||||
case .plus; #through;
|
||||
|
|
@ -663,10 +654,10 @@ parse_expression_unary :: (p: *Parser) -> *Node {
|
|||
return parse_expression_postfix(p);
|
||||
}
|
||||
|
||||
parse_expression_postfix :: (p: *Parser) -> *Node {
|
||||
parse_expression_postfix :: (p: *Vm) -> *Node {
|
||||
// @TODO
|
||||
base := parse_expression_base(p);
|
||||
basic.assert(base != null, "expected expression"); // @errors
|
||||
if base == null return null;
|
||||
|
||||
t := peek_token(p);
|
||||
if t.kind == {
|
||||
|
|
@ -717,9 +708,9 @@ parse_expression_postfix :: (p: *Parser) -> *Node {
|
|||
return base;
|
||||
}
|
||||
|
||||
parse_expression_base :: (p: *Parser) -> *Node {
|
||||
parse_expression_base :: (p: *Vm) -> *Node {
|
||||
t, ok := expect_token(p, .kw_true, .kw_false, .number, .symbol, .l_paren);
|
||||
basic.assert(ok, "expected expression, found '%'", t.str); // @errors
|
||||
if !ok return null;
|
||||
|
||||
if t.kind == {
|
||||
case .kw_true; #through;
|
||||
|
|
@ -742,7 +733,10 @@ parse_expression_base :: (p: *Parser) -> *Node {
|
|||
node.value_kind = .float;
|
||||
|
||||
value, ok := strings.parse_float(*copy);
|
||||
basic.assert(ok, "malformed float '%'", t.str); // @errors
|
||||
if !ok {
|
||||
report(p, "malformed float '%'", t.str); // @location
|
||||
return null;
|
||||
}
|
||||
|
||||
node.f = value;
|
||||
}
|
||||
|
|
@ -753,7 +747,10 @@ parse_expression_base :: (p: *Parser) -> *Node {
|
|||
}
|
||||
|
||||
value, ok := strings.parse_int(*copy);
|
||||
basic.assert(ok, "malformed integer '%'", t.str); // @errors
|
||||
if !ok {
|
||||
report(p, "malformed integer '%'", t.str); // @location
|
||||
return null;
|
||||
}
|
||||
|
||||
node.i = value;
|
||||
}
|
||||
|
|
@ -762,10 +759,16 @@ parse_expression_base :: (p: *Parser) -> *Node {
|
|||
|
||||
case .l_paren;
|
||||
node := parse_expression(p);
|
||||
basic.assert(node != null, "expected expression"); // @errors
|
||||
if node == null {
|
||||
report(p, "expected an expression after '('");
|
||||
return null;
|
||||
}
|
||||
|
||||
_, ok := expect_token(p, .r_paren);
|
||||
basic.assert(ok, "expected ')'"); // @errors
|
||||
t, ok := expect_token(p, .r_paren);
|
||||
if !ok {
|
||||
report(p, "expected ')', found '%'", t.str); // @errors
|
||||
return null;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
|
@ -773,29 +776,29 @@ parse_expression_base :: (p: *Parser) -> *Node {
|
|||
return null;
|
||||
}
|
||||
|
||||
make_node :: (p: *Parser, $T: Type) -> *T {
|
||||
node := mem.request_memory(T,, allocator = p.allocator);
|
||||
make_node :: (p: *Vm, $T: Type) -> *T {
|
||||
node := mem.request_memory(T,, allocator = p.parser_allocator);
|
||||
|
||||
#if #exists(T.init) {
|
||||
T.init(node, p.allocator);
|
||||
T.init(node, p.parser_allocator);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
make_node :: (p: *Parser, $type_kind: Node_Type.Type_Kind) -> *Node_Type {
|
||||
type := mem.request_memory(Node_Type,, allocator = p.allocator);
|
||||
make_node :: (p: *Vm, $type_kind: Node_Type.Type_Kind) -> *Node_Type {
|
||||
type := mem.request_memory(Node_Type,, allocator = p.parser_allocator);
|
||||
type.type_kind = type_kind;
|
||||
Node_Type.init(type, p.allocator);
|
||||
Node_Type.init(type, p.parser_allocator);
|
||||
return type;
|
||||
}
|
||||
|
||||
peek_token :: (p: *Parser) -> Token {
|
||||
peek_token :: (p: *Vm) -> Token {
|
||||
copy := p.*;
|
||||
return consume_token(*copy);
|
||||
}
|
||||
|
||||
at_end :: (p: *Parser) -> bool {
|
||||
at_end :: (p: *Vm) -> bool {
|
||||
return p.offset >= p.source.count;
|
||||
}
|
||||
|
||||
|
|
@ -815,8 +818,10 @@ continues_number :: (c: u8) -> bool {
|
|||
return starts_number(c) || c == ".";
|
||||
}
|
||||
|
||||
consume_token :: (p: *Parser) -> Token {
|
||||
if at_end(p) return .{ kind = .end_of_file };
|
||||
consume_token :: (p: *Vm) -> Token {
|
||||
if at_end(p) {
|
||||
return .{ kind = .end_of_file };
|
||||
}
|
||||
|
||||
c := p.source[p.offset];
|
||||
|
||||
|
|
@ -947,7 +952,7 @@ consume_token :: (p: *Parser) -> Token {
|
|||
return .{ kind = .invalid, str = s };
|
||||
}
|
||||
|
||||
expect_token :: (p: *Parser, kinds: ..Token.Kind) -> Token, bool {
|
||||
expect_token :: (p: *Vm, kinds: ..Token.Kind) -> Token, bool {
|
||||
t := consume_token(p);
|
||||
for kinds if it == t.kind {
|
||||
return t, true;
|
||||
|
|
@ -956,7 +961,7 @@ expect_token :: (p: *Parser, kinds: ..Token.Kind) -> Token, bool {
|
|||
return t, false;
|
||||
}
|
||||
|
||||
try_lazy_init :: (p: *Parser) {
|
||||
mem.lazy_set_allocator(p);
|
||||
mem.lazy_set_allocator(*p.toplevel);
|
||||
try_lazy_init :: (p: *Vm) {
|
||||
mem.lazy_set_allocator(*p.toplevel, p.parser_allocator);
|
||||
mem.lazy_set_allocator(*p.reports, p.parser_allocator);
|
||||
}
|
||||
2
x/vm/resolver.jai
Normal file
2
x/vm/resolver.jai
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
resolve_everything :: (vm: *Vm) {
|
||||
}
|
||||
Loading…
Reference in a new issue