clean
This commit is contained in:
@@ -190,7 +190,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
GLSL;
|
GLSL;
|
||||||
|
|
||||||
program : u32 = create_program(vert_src, frag_src);
|
program := create_program(vert_src, frag_src);
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
|
|
||||||
mvp_loc : s32 = glGetUniformLocation(program, "uMVP");
|
mvp_loc : s32 = glGetUniformLocation(program, "uMVP");
|
||||||
@@ -200,7 +200,7 @@ GLSL;
|
|||||||
// Cube vertices: pos(vec4 w=1) + normal(vec4 w=0), 36 vertices × 2 vec4s = 72
|
// Cube vertices: pos(vec4 w=1) + normal(vec4 w=0), 36 vertices × 2 vec4s = 72
|
||||||
vertices : []Vector(4, f32) = .[
|
vertices : []Vector(4, f32) = .[
|
||||||
// Front face (z = +0.5)
|
// Front face (z = +0.5)
|
||||||
vec4(-0.5, -0.5, 0.5, 1.0), vec4( 0.0, 0.0, 1.0, 0.0),
|
.[-0.5, -0.5, 0.5, 1.0], vec4( 0.0, 0.0, 1.0, 0.0),
|
||||||
vec4( 0.5, -0.5, 0.5, 1.0), vec4( 0.0, 0.0, 1.0, 0.0),
|
vec4( 0.5, -0.5, 0.5, 1.0), vec4( 0.0, 0.0, 1.0, 0.0),
|
||||||
vec4( 0.5, 0.5, 0.5, 1.0), vec4( 0.0, 0.0, 1.0, 0.0),
|
vec4( 0.5, 0.5, 0.5, 1.0), vec4( 0.0, 0.0, 1.0, 0.0),
|
||||||
vec4(-0.5, -0.5, 0.5, 1.0), vec4( 0.0, 0.0, 1.0, 0.0),
|
vec4(-0.5, -0.5, 0.5, 1.0), vec4( 0.0, 0.0, 1.0, 0.0),
|
||||||
@@ -246,6 +246,7 @@ GLSL;
|
|||||||
// Create VAO and VBO
|
// Create VAO and VBO
|
||||||
vao : u32 = 0;
|
vao : u32 = 0;
|
||||||
vbo : u32 = 0;
|
vbo : u32 = 0;
|
||||||
|
|
||||||
glGenVertexArrays(1, vao);
|
glGenVertexArrays(1, vao);
|
||||||
glGenBuffers(1, vbo);
|
glGenBuffers(1, vbo);
|
||||||
|
|
||||||
@@ -276,6 +277,7 @@ GLSL;
|
|||||||
case .key_up: (e) {
|
case .key_up: (e) {
|
||||||
if e.key == {
|
if e.key == {
|
||||||
case .escape: running = false;
|
case .escape: running = false;
|
||||||
|
//case .
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .window_exposed: (e) {
|
case .window_exposed: (e) {
|
||||||
|
|||||||
1039
src/codegen.zig
1039
src/codegen.zig
File diff suppressed because it is too large
Load Diff
280
src/comptime.zig
280
src/comptime.zig
@@ -57,6 +57,18 @@ pub const Value = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn asIndex(self: Value) !usize {
|
||||||
|
return @intCast(self.asInt() orelse return error.TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isTruthy(self: Value) bool {
|
||||||
|
return switch (self) {
|
||||||
|
.bool_val => |bv| bv,
|
||||||
|
.int_val => |iv| iv != 0,
|
||||||
|
else => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn asFloat(self: Value) ?f64 {
|
pub fn asFloat(self: Value) ?f64 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.float_val => |v| v,
|
.float_val => |v| v,
|
||||||
@@ -312,6 +324,18 @@ pub const Compiler = struct {
|
|||||||
try self.instructions.append(self.allocator, instruction);
|
try self.instructions.append(self.allocator, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn patchJump(self: *Compiler, idx: usize) void {
|
||||||
|
self.instructions.items[idx] = .{ .jump = @intCast(@as(i64, @intCast(self.instructions.items.len)) - @as(i64, @intCast(idx)) - 1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patchJumpIfFalse(self: *Compiler, idx: usize) void {
|
||||||
|
self.instructions.items[idx] = .{ .jump_if_false = @intCast(@as(i64, @intCast(self.instructions.items.len)) - @as(i64, @intCast(idx)) - 1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patchJumpIfTrue(self: *Compiler, idx: usize) void {
|
||||||
|
self.instructions.items[idx] = .{ .jump_if_true = @intCast(@as(i64, @intCast(self.instructions.items.len)) - @as(i64, @intCast(idx)) - 1) };
|
||||||
|
}
|
||||||
|
|
||||||
fn addString(self: *Compiler, str: []const u8) !u32 {
|
fn addString(self: *Compiler, str: []const u8) !u32 {
|
||||||
const idx: u32 = @intCast(self.strings.items.len);
|
const idx: u32 = @intCast(self.strings.items.len);
|
||||||
try self.strings.append(self.allocator, str);
|
try self.strings.append(self.allocator, str);
|
||||||
@@ -399,9 +423,7 @@ pub const Compiler = struct {
|
|||||||
try self.emit(.{ .jump_if_false = 0 });
|
try self.emit(.{ .jump_if_false = 0 });
|
||||||
try self.emit(.pop);
|
try self.emit(.pop);
|
||||||
try self.compileNode(binop.rhs);
|
try self.compileNode(binop.rhs);
|
||||||
self.instructions.items[jump_idx] = .{
|
self.patchJumpIfFalse(jump_idx);
|
||||||
.jump_if_false = @intCast(@as(i64, @intCast(self.instructions.items.len)) - @as(i64, @intCast(jump_idx)) - 1),
|
|
||||||
};
|
|
||||||
} else if (binop.op == .or_op) {
|
} else if (binop.op == .or_op) {
|
||||||
// Short-circuit OR: LHS, dup, jump_if_true +N, pop, RHS
|
// Short-circuit OR: LHS, dup, jump_if_true +N, pop, RHS
|
||||||
try self.compileNode(binop.lhs);
|
try self.compileNode(binop.lhs);
|
||||||
@@ -410,9 +432,7 @@ pub const Compiler = struct {
|
|||||||
try self.emit(.{ .jump_if_true = 0 });
|
try self.emit(.{ .jump_if_true = 0 });
|
||||||
try self.emit(.pop);
|
try self.emit(.pop);
|
||||||
try self.compileNode(binop.rhs);
|
try self.compileNode(binop.rhs);
|
||||||
self.instructions.items[jump_idx] = .{
|
self.patchJumpIfTrue(jump_idx);
|
||||||
.jump_if_true = @intCast(@as(i64, @intCast(self.instructions.items.len)) - @as(i64, @intCast(jump_idx)) - 1),
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
try self.compileNode(binop.lhs);
|
try self.compileNode(binop.lhs);
|
||||||
try self.compileNode(binop.rhs);
|
try self.compileNode(binop.rhs);
|
||||||
@@ -465,9 +485,7 @@ pub const Compiler = struct {
|
|||||||
.neq => .neq,
|
.neq => .neq,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
});
|
});
|
||||||
self.instructions.items[jump_idx] = .{
|
self.patchJumpIfFalse(jump_idx);
|
||||||
.jump_if_false = @intCast(@as(i64, @intCast(self.instructions.items.len)) - @as(i64, @intCast(jump_idx)) - 1),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unary_op => |unop| {
|
.unary_op => |unop| {
|
||||||
@@ -608,14 +626,11 @@ pub const Compiler = struct {
|
|||||||
if (ie.else_branch) |eb| {
|
if (ie.else_branch) |eb| {
|
||||||
const jump_end_idx = self.instructions.items.len;
|
const jump_end_idx = self.instructions.items.len;
|
||||||
try self.emit(.{ .jump = 0 }); // placeholder
|
try self.emit(.{ .jump = 0 }); // placeholder
|
||||||
// Patch jump_if_false to here
|
self.patchJumpIfFalse(jump_false_idx);
|
||||||
self.instructions.items[jump_false_idx] = .{ .jump_if_false = @intCast(self.instructions.items.len - jump_false_idx - 1) };
|
|
||||||
try self.compileNode(eb);
|
try self.compileNode(eb);
|
||||||
// Patch jump to end
|
self.patchJump(jump_end_idx);
|
||||||
self.instructions.items[jump_end_idx] = .{ .jump = @intCast(self.instructions.items.len - jump_end_idx - 1) };
|
|
||||||
} else {
|
} else {
|
||||||
// Patch jump_if_false to here
|
self.patchJumpIfFalse(jump_false_idx);
|
||||||
self.instructions.items[jump_false_idx] = .{ .jump_if_false = @intCast(self.instructions.items.len - jump_false_idx - 1) };
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.call => |call_node| {
|
.call => |call_node| {
|
||||||
@@ -637,18 +652,8 @@ pub const Compiler = struct {
|
|||||||
if (callee_name) |name| {
|
if (callee_name) |name| {
|
||||||
// Check if it's a builtin
|
// Check if it's a builtin
|
||||||
const base = if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name;
|
const base = if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name;
|
||||||
if (std.mem.eql(u8, base, "print")) {
|
if (std.meta.stringToEnum(BuiltinId, base)) |id| {
|
||||||
try self.emit(.{ .call_builtin = .{ .id = .print, .arg_count = @intCast(call_node.args.len) } });
|
try self.emit(.{ .call_builtin = .{ .id = id, .arg_count = @intCast(call_node.args.len) } });
|
||||||
} else if (std.mem.eql(u8, base, "write")) {
|
|
||||||
try self.emit(.{ .call_builtin = .{ .id = .write, .arg_count = @intCast(call_node.args.len) } });
|
|
||||||
} else if (std.mem.eql(u8, base, "sqrt")) {
|
|
||||||
try self.emit(.{ .call_builtin = .{ .id = .sqrt, .arg_count = @intCast(call_node.args.len) } });
|
|
||||||
} else if (std.mem.eql(u8, base, "size_of")) {
|
|
||||||
try self.emit(.{ .call_builtin = .{ .id = .size_of, .arg_count = @intCast(call_node.args.len) } });
|
|
||||||
} else if (std.mem.eql(u8, base, "cast")) {
|
|
||||||
try self.emit(.{ .call_builtin = .{ .id = .cast, .arg_count = @intCast(call_node.args.len) } });
|
|
||||||
} else if (std.mem.eql(u8, base, "alloc")) {
|
|
||||||
try self.emit(.{ .call_builtin = .{ .id = .alloc, .arg_count = @intCast(call_node.args.len) } });
|
|
||||||
} else {
|
} else {
|
||||||
try self.emit(.{ .call = .{ .func_name = name, .arg_count = @intCast(call_node.args.len) } });
|
try self.emit(.{ .call = .{ .func_name = name, .arg_count = @intCast(call_node.args.len) } });
|
||||||
}
|
}
|
||||||
@@ -670,8 +675,7 @@ pub const Compiler = struct {
|
|||||||
try self.compileNode(arm.body);
|
try self.compileNode(arm.body);
|
||||||
try end_jumps.append(self.allocator, self.instructions.items.len);
|
try end_jumps.append(self.allocator, self.instructions.items.len);
|
||||||
try self.emit(.{ .jump = 0 }); // placeholder jump to end
|
try self.emit(.{ .jump = 0 }); // placeholder jump to end
|
||||||
// Patch jump_if_false
|
self.patchJumpIfFalse(jump_next_idx);
|
||||||
self.instructions.items[jump_next_idx] = .{ .jump_if_false = @intCast(self.instructions.items.len - jump_next_idx - 1) };
|
|
||||||
} else {
|
} else {
|
||||||
// else arm: unconditionally execute body
|
// else arm: unconditionally execute body
|
||||||
try self.emit(.pop); // pop the subject copy
|
try self.emit(.pop); // pop the subject copy
|
||||||
@@ -683,7 +687,7 @@ pub const Compiler = struct {
|
|||||||
try self.emit(.pop); // pop remaining subject
|
try self.emit(.pop); // pop remaining subject
|
||||||
// Patch all end jumps
|
// Patch all end jumps
|
||||||
for (end_jumps.items) |idx| {
|
for (end_jumps.items) |idx| {
|
||||||
self.instructions.items[idx] = .{ .jump = @intCast(self.instructions.items.len - idx - 1) };
|
self.patchJump(idx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.struct_literal => |sl| {
|
.struct_literal => |sl| {
|
||||||
@@ -772,12 +776,11 @@ pub const Compiler = struct {
|
|||||||
try self.emit(.{ .jump = back_offset });
|
try self.emit(.{ .jump = back_offset });
|
||||||
|
|
||||||
// Patch jump_if_false to after the loop
|
// Patch jump_if_false to after the loop
|
||||||
const after_loop = self.instructions.items.len;
|
self.patchJumpIfFalse(jump_false_idx);
|
||||||
self.instructions.items[jump_false_idx] = .{ .jump_if_false = @intCast(after_loop - jump_false_idx - 1) };
|
|
||||||
|
|
||||||
// Patch all break jumps to after the loop
|
// Patch all break jumps to after the loop
|
||||||
for (self.break_patches.items) |patch_idx| {
|
for (self.break_patches.items) |patch_idx| {
|
||||||
self.instructions.items[patch_idx] = .{ .jump = @as(i32, @intCast(after_loop)) - @as(i32, @intCast(patch_idx)) - 1 };
|
self.patchJump(patch_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore outer loop context
|
// Restore outer loop context
|
||||||
@@ -942,7 +945,7 @@ pub const VM = struct {
|
|||||||
.address_of_index => {
|
.address_of_index => {
|
||||||
const idx_val = try self.pop();
|
const idx_val = try self.pop();
|
||||||
const arr = try self.pop();
|
const arr = try self.pop();
|
||||||
const idx: usize = @intCast(idx_val.asInt() orelse return error.TypeError);
|
const idx: usize = try idx_val.asIndex();
|
||||||
if (arr == .array_val) {
|
if (arr == .array_val) {
|
||||||
if (idx >= arr.array_val.elements.len) return error.IndexOutOfBounds;
|
if (idx >= arr.array_val.elements.len) return error.IndexOutOfBounds;
|
||||||
try self.push(.{ .pointer_val = .{ .target = arr.array_val.elements.ptr + idx } });
|
try self.push(.{ .pointer_val = .{ .target = arr.array_val.elements.ptr + idx } });
|
||||||
@@ -980,31 +983,11 @@ pub const VM = struct {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Arithmetic
|
// Arithmetic
|
||||||
.add => {
|
.add => try self.execArith(.add_op),
|
||||||
const b = try self.pop();
|
.sub => try self.execArith(.sub_op),
|
||||||
const a = try self.pop();
|
.mul => try self.execArith(.mul_op),
|
||||||
try self.push(try self.arith(a, b, .add_op));
|
.div => try self.execArith(.div_op),
|
||||||
},
|
.mod => try self.execArith(.mod_op),
|
||||||
.sub => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(try self.arith(a, b, .sub_op));
|
|
||||||
},
|
|
||||||
.mul => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(try self.arith(a, b, .mul_op));
|
|
||||||
},
|
|
||||||
.div => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(try self.arith(a, b, .div_op));
|
|
||||||
},
|
|
||||||
.mod => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(try self.arith(a, b, .mod_op));
|
|
||||||
},
|
|
||||||
.bit_and => {
|
.bit_and => {
|
||||||
const b = try self.pop();
|
const b = try self.pop();
|
||||||
const a = try self.pop();
|
const a = try self.pop();
|
||||||
@@ -1030,44 +1013,15 @@ pub const VM = struct {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Comparison
|
// Comparison
|
||||||
.eq => {
|
.eq => try self.execComparison(.eq),
|
||||||
const b = try self.pop();
|
.neq => try self.execComparison(.neq),
|
||||||
const a = try self.pop();
|
.lt => try self.execComparison(.lt),
|
||||||
try self.push(.{ .bool_val = self.valEqual(a, b) });
|
.lte => try self.execComparison(.lte),
|
||||||
},
|
.gt => try self.execComparison(.gt),
|
||||||
.neq => {
|
.gte => try self.execComparison(.gte),
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(.{ .bool_val = !self.valEqual(a, b) });
|
|
||||||
},
|
|
||||||
.lt => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(.{ .bool_val = self.valLess(a, b) });
|
|
||||||
},
|
|
||||||
.lte => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(.{ .bool_val = self.valLess(a, b) or self.valEqual(a, b) });
|
|
||||||
},
|
|
||||||
.gt => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(.{ .bool_val = self.valLess(b, a) });
|
|
||||||
},
|
|
||||||
.gte => {
|
|
||||||
const b = try self.pop();
|
|
||||||
const a = try self.pop();
|
|
||||||
try self.push(.{ .bool_val = self.valLess(b, a) or self.valEqual(a, b) });
|
|
||||||
},
|
|
||||||
.not => {
|
.not => {
|
||||||
const v = try self.pop();
|
const v = try self.pop();
|
||||||
const b = switch (v) {
|
try self.push(.{ .bool_val = !v.isTruthy() });
|
||||||
.bool_val => |bv| bv,
|
|
||||||
.int_val => |iv| iv != 0,
|
|
||||||
else => true,
|
|
||||||
};
|
|
||||||
try self.push(.{ .bool_val = !b });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Control flow
|
// Control flow
|
||||||
@@ -1076,23 +1030,13 @@ pub const VM = struct {
|
|||||||
},
|
},
|
||||||
.jump_if_false => |offset| {
|
.jump_if_false => |offset| {
|
||||||
const v = try self.pop();
|
const v = try self.pop();
|
||||||
const is_true = switch (v) {
|
if (!v.isTruthy()) {
|
||||||
.bool_val => |bv| bv,
|
|
||||||
.int_val => |iv| iv != 0,
|
|
||||||
else => true,
|
|
||||||
};
|
|
||||||
if (!is_true) {
|
|
||||||
frame.ip = @intCast(@as(i64, frame.ip) + offset);
|
frame.ip = @intCast(@as(i64, frame.ip) + offset);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.jump_if_true => |offset| {
|
.jump_if_true => |offset| {
|
||||||
const v = try self.pop();
|
const v = try self.pop();
|
||||||
const is_true = switch (v) {
|
if (v.isTruthy()) {
|
||||||
.bool_val => |bv| bv,
|
|
||||||
.int_val => |iv| iv != 0,
|
|
||||||
else => true,
|
|
||||||
};
|
|
||||||
if (is_true) {
|
|
||||||
frame.ip = @intCast(@as(i64, frame.ip) + offset);
|
frame.ip = @intCast(@as(i64, frame.ip) + offset);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1187,7 +1131,7 @@ pub const VM = struct {
|
|||||||
const idx_val = try self.pop();
|
const idx_val = try self.pop();
|
||||||
const arr = try self.pop();
|
const arr = try self.pop();
|
||||||
if (arr == .array_val) {
|
if (arr == .array_val) {
|
||||||
const idx: usize = @intCast(idx_val.asInt() orelse return error.TypeError);
|
const idx: usize = try idx_val.asIndex();
|
||||||
if (idx < arr.array_val.elements.len) {
|
if (idx < arr.array_val.elements.len) {
|
||||||
try self.push(arr.array_val.elements[idx]);
|
try self.push(arr.array_val.elements[idx]);
|
||||||
} else {
|
} else {
|
||||||
@@ -1195,7 +1139,7 @@ pub const VM = struct {
|
|||||||
}
|
}
|
||||||
} else if (arr == .string_val) {
|
} else if (arr == .string_val) {
|
||||||
// String indexing: return byte as int
|
// String indexing: return byte as int
|
||||||
const idx: usize = @intCast(idx_val.asInt() orelse return error.TypeError);
|
const idx: usize = try idx_val.asIndex();
|
||||||
if (idx < arr.string_val.len) {
|
if (idx < arr.string_val.len) {
|
||||||
try self.push(.{ .int_val = @intCast(arr.string_val[idx]) });
|
try self.push(.{ .int_val = @intCast(arr.string_val[idx]) });
|
||||||
} else {
|
} else {
|
||||||
@@ -1203,7 +1147,7 @@ pub const VM = struct {
|
|||||||
}
|
}
|
||||||
} else if (arr == .pointer_val) {
|
} else if (arr == .pointer_val) {
|
||||||
// Many-pointer indexing: ptr[i]
|
// Many-pointer indexing: ptr[i]
|
||||||
const idx: usize = @intCast(idx_val.asInt() orelse return error.TypeError);
|
const idx: usize = try idx_val.asIndex();
|
||||||
try self.push(arr.pointer_val.target[idx]);
|
try self.push(arr.pointer_val.target[idx]);
|
||||||
} else {
|
} else {
|
||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
@@ -1214,14 +1158,14 @@ pub const VM = struct {
|
|||||||
const idx_val = try self.pop();
|
const idx_val = try self.pop();
|
||||||
const arr = try self.pop();
|
const arr = try self.pop();
|
||||||
if (arr == .array_val) {
|
if (arr == .array_val) {
|
||||||
const idx: usize = @intCast(idx_val.asInt() orelse return error.TypeError);
|
const idx: usize = try idx_val.asIndex();
|
||||||
if (idx < arr.array_val.elements.len) {
|
if (idx < arr.array_val.elements.len) {
|
||||||
arr.array_val.elements[idx] = val;
|
arr.array_val.elements[idx] = val;
|
||||||
}
|
}
|
||||||
try self.push(arr);
|
try self.push(arr);
|
||||||
} else if (arr == .string_val) {
|
} else if (arr == .string_val) {
|
||||||
// String index assignment: mutate byte
|
// String index assignment: mutate byte
|
||||||
const idx: usize = @intCast(idx_val.asInt() orelse return error.TypeError);
|
const idx: usize = try idx_val.asIndex();
|
||||||
const byte_val: u8 = @intCast(val.asInt() orelse return error.TypeError);
|
const byte_val: u8 = @intCast(val.asInt() orelse return error.TypeError);
|
||||||
if (idx < arr.string_val.len) {
|
if (idx < arr.string_val.len) {
|
||||||
const mutable = @constCast(arr.string_val);
|
const mutable = @constCast(arr.string_val);
|
||||||
@@ -1230,7 +1174,7 @@ pub const VM = struct {
|
|||||||
try self.push(arr);
|
try self.push(arr);
|
||||||
} else if (arr == .pointer_val) {
|
} else if (arr == .pointer_val) {
|
||||||
// Many-pointer index assignment: ptr[i] = val
|
// Many-pointer index assignment: ptr[i] = val
|
||||||
const idx: usize = @intCast(idx_val.asInt() orelse return error.TypeError);
|
const idx: usize = try idx_val.asIndex();
|
||||||
arr.pointer_val.target[idx] = val;
|
arr.pointer_val.target[idx] = val;
|
||||||
try self.push(arr);
|
try self.push(arr);
|
||||||
} else {
|
} else {
|
||||||
@@ -1260,6 +1204,28 @@ pub const VM = struct {
|
|||||||
|
|
||||||
const ArithOp = enum { add_op, sub_op, mul_op, div_op, mod_op };
|
const ArithOp = enum { add_op, sub_op, mul_op, div_op, mod_op };
|
||||||
|
|
||||||
|
fn execArith(self: *VM, op: ArithOp) !void {
|
||||||
|
const b = try self.pop();
|
||||||
|
const a = try self.pop();
|
||||||
|
try self.push(try self.arith(a, b, op));
|
||||||
|
}
|
||||||
|
|
||||||
|
const CmpOp = enum { eq, neq, lt, lte, gt, gte };
|
||||||
|
|
||||||
|
fn execComparison(self: *VM, comptime op: CmpOp) !void {
|
||||||
|
const b = try self.pop();
|
||||||
|
const a = try self.pop();
|
||||||
|
const result = switch (op) {
|
||||||
|
.eq => self.valEqual(a, b),
|
||||||
|
.neq => !self.valEqual(a, b),
|
||||||
|
.lt => self.valLess(a, b),
|
||||||
|
.lte => self.valLess(a, b) or self.valEqual(a, b),
|
||||||
|
.gt => self.valLess(b, a),
|
||||||
|
.gte => self.valLess(b, a) or self.valEqual(a, b),
|
||||||
|
};
|
||||||
|
try self.push(.{ .bool_val = result });
|
||||||
|
}
|
||||||
|
|
||||||
fn arith(self: *VM, a: Value, b: Value, op: ArithOp) !Value {
|
fn arith(self: *VM, a: Value, b: Value, op: ArithOp) !Value {
|
||||||
_ = self;
|
_ = self;
|
||||||
// Both int
|
// Both int
|
||||||
@@ -1357,27 +1323,13 @@ pub const VM = struct {
|
|||||||
for (self.root_decls) |decl| {
|
for (self.root_decls) |decl| {
|
||||||
switch (decl.data) {
|
switch (decl.data) {
|
||||||
.fn_decl => |fd| {
|
.fn_decl => |fd| {
|
||||||
if (std.mem.eql(u8, fd.name, name)) {
|
if (std.mem.eql(u8, fd.name, name))
|
||||||
var compiler = Compiler.init(self.allocator, self.sema_result, self.root_decls, self.codegen);
|
return self.compileFunctionAndInvoke(name, fd, arg_count);
|
||||||
const chunk = try compiler.compileFunction(fd);
|
|
||||||
try self.functions.put(name, chunk);
|
|
||||||
if (self.functions.getPtr(name)) |ptr| {
|
|
||||||
return self.invokeChunk(ptr, arg_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.namespace_decl => |ns| {
|
.namespace_decl => |ns| {
|
||||||
for (ns.decls) |d| {
|
for (ns.decls) |d| {
|
||||||
if (d.data == .fn_decl) {
|
if (d.data == .fn_decl and std.mem.eql(u8, d.data.fn_decl.name, name))
|
||||||
if (std.mem.eql(u8, d.data.fn_decl.name, name)) {
|
return self.compileFunctionAndInvoke(name, d.data.fn_decl, arg_count);
|
||||||
var compiler = Compiler.init(self.allocator, self.sema_result, self.root_decls, self.codegen);
|
|
||||||
const chunk = try compiler.compileFunction(d.data.fn_decl);
|
|
||||||
try self.functions.put(name, chunk);
|
|
||||||
if (self.functions.getPtr(name)) |ptr| {
|
|
||||||
return self.invokeChunk(ptr, arg_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
@@ -1553,6 +1505,29 @@ pub const VM = struct {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cacheTypeGlobal(self: *VM, name: []const u8, ty: Type) VMError!Value {
|
||||||
|
const val = Value{ .type_val = ty };
|
||||||
|
try self.globals.put(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compileAndEvalGlobal(self: *VM, name: []const u8, expr: *Node) VMError!Value {
|
||||||
|
var compiler = Compiler.init(self.allocator, self.sema_result, self.root_decls, self.codegen);
|
||||||
|
const chunk = compiler.compile(expr) catch return error.CompileError;
|
||||||
|
const result = self.evalInFreshVM(&chunk) catch return error.CompileError;
|
||||||
|
try self.globals.put(name, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compileFunctionAndInvoke(self: *VM, name: []const u8, fd: ast.FnDecl, arg_count: u8) !void {
|
||||||
|
var compiler = Compiler.init(self.allocator, self.sema_result, self.root_decls, self.codegen);
|
||||||
|
const chunk = try compiler.compileFunction(fd);
|
||||||
|
try self.functions.put(name, chunk);
|
||||||
|
if (self.functions.getPtr(name)) |ptr| {
|
||||||
|
return self.invokeChunk(ptr, arg_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveGlobal(self: *VM, name: []const u8) VMError!Value {
|
fn resolveGlobal(self: *VM, name: []const u8) VMError!Value {
|
||||||
// Check cache first
|
// Check cache first
|
||||||
if (self.globals.get(name)) |val| return val;
|
if (self.globals.get(name)) |val| return val;
|
||||||
@@ -1562,21 +1537,13 @@ pub const VM = struct {
|
|||||||
switch (decl.data) {
|
switch (decl.data) {
|
||||||
.const_decl => |cd| {
|
.const_decl => |cd| {
|
||||||
if (std.mem.eql(u8, cd.name, name)) {
|
if (std.mem.eql(u8, cd.name, name)) {
|
||||||
var compiler = Compiler.init(self.allocator, self.sema_result, self.root_decls, self.codegen);
|
return self.compileAndEvalGlobal(name, cd.value);
|
||||||
const chunk = compiler.compile(cd.value) catch return error.CompileError;
|
|
||||||
const result = self.evalInFreshVM(&chunk) catch return error.CompileError;
|
|
||||||
try self.globals.put(name, result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.var_decl => |vd| {
|
.var_decl => |vd| {
|
||||||
if (std.mem.eql(u8, vd.name, name)) {
|
if (std.mem.eql(u8, vd.name, name)) {
|
||||||
if (vd.value) |val_expr| {
|
if (vd.value) |val_expr| {
|
||||||
var compiler = Compiler.init(self.allocator, self.sema_result, self.root_decls, self.codegen);
|
return self.compileAndEvalGlobal(name, val_expr);
|
||||||
const chunk = compiler.compile(val_expr) catch return error.CompileError;
|
|
||||||
const result = self.evalInFreshVM(&chunk) catch return error.CompileError;
|
|
||||||
try self.globals.put(name, result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
return .{ .void_val = {} };
|
return .{ .void_val = {} };
|
||||||
}
|
}
|
||||||
@@ -1585,11 +1552,7 @@ pub const VM = struct {
|
|||||||
// Check inside namespace for matching declarations
|
// Check inside namespace for matching declarations
|
||||||
for (ns.decls) |d| {
|
for (ns.decls) |d| {
|
||||||
if (d.data == .const_decl and std.mem.eql(u8, d.data.const_decl.name, name)) {
|
if (d.data == .const_decl and std.mem.eql(u8, d.data.const_decl.name, name)) {
|
||||||
var compiler = Compiler.init(self.allocator, self.sema_result, self.root_decls, self.codegen);
|
return self.compileAndEvalGlobal(name, d.data.const_decl.value);
|
||||||
const chunk = compiler.compile(d.data.const_decl.value) catch return error.CompileError;
|
|
||||||
const result = self.evalInFreshVM(&chunk) catch return error.CompileError;
|
|
||||||
try self.globals.put(name, result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1601,37 +1564,26 @@ pub const VM = struct {
|
|||||||
for (self.root_decls) |decl| {
|
for (self.root_decls) |decl| {
|
||||||
switch (decl.data) {
|
switch (decl.data) {
|
||||||
.struct_decl => |sd| {
|
.struct_decl => |sd| {
|
||||||
if (std.mem.eql(u8, sd.name, name)) {
|
if (std.mem.eql(u8, sd.name, name))
|
||||||
const val = Value{ .type_val = .{ .struct_type = name } };
|
return self.cacheTypeGlobal(name, .{ .struct_type = name });
|
||||||
try self.globals.put(name, val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.enum_decl => |ed| {
|
.enum_decl => |ed| {
|
||||||
if (std.mem.eql(u8, ed.name, name)) {
|
if (std.mem.eql(u8, ed.name, name)) {
|
||||||
const ty: Type = if (ed.variant_types.len > 0) .{ .union_type = name } else .{ .enum_type = name };
|
const ty: Type = if (ed.variant_types.len > 0) .{ .union_type = name } else .{ .enum_type = name };
|
||||||
const val = Value{ .type_val = ty };
|
return self.cacheTypeGlobal(name, ty);
|
||||||
try self.globals.put(name, val);
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.union_decl => |ud| {
|
.union_decl => |ud| {
|
||||||
if (std.mem.eql(u8, ud.name, name)) {
|
if (std.mem.eql(u8, ud.name, name))
|
||||||
const val = Value{ .type_val = .{ .union_type = name } };
|
return self.cacheTypeGlobal(name, .{ .union_type = name });
|
||||||
try self.globals.put(name, val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's a primitive type name (s32, f64, bool, etc.)
|
// Check if it's a primitive type name (s32, f64, bool, etc.)
|
||||||
if (Type.fromName(name)) |ty| {
|
if (Type.fromName(name)) |ty|
|
||||||
const val = Value{ .type_val = ty };
|
return self.cacheTypeGlobal(name, ty);
|
||||||
try self.globals.put(name, val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error.UndefinedVariable;
|
return error.UndefinedVariable;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user