move vm to x

This commit is contained in:
Judah Caruso 2025-07-17 08:31:29 -06:00
parent 90590b964a
commit 3adbcab494
5 changed files with 259 additions and 151 deletions

View file

@ -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";
// }

View file

@ -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
View 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";
// }

View file

@ -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
View file

@ -0,0 +1,2 @@
resolve_everything :: (vm: *Vm) {
}