From eb9552c390d32f0c9e2874cf5629cbc636f8bff5 Mon Sep 17 00:00:00 2001 From: kayomn Date: Mon, 6 Nov 2023 20:53:24 +0000 Subject: [PATCH] Merge compiler into Chunk.zig --- source/ona/kym/Chunk.zig | 408 ++++++++++++++++++++++++++++++++++- source/ona/kym/Compiler.zig | 413 ------------------------------------ 2 files changed, 406 insertions(+), 415 deletions(-) delete mode 100644 source/ona/kym/Compiler.zig diff --git a/source/ona/kym/Chunk.zig b/source/ona/kym/Chunk.zig index bcfd649..7ebb7fb 100644 --- a/source/ona/kym/Chunk.zig +++ b/source/ona/kym/Chunk.zig @@ -1,6 +1,8 @@ -const app = @import("../app.zig"); +const Expr = @import("./Expr.zig"); -const Compiler = @import("./Compiler.zig"); +const Stmt = @import("./Stmt.zig"); + +const app = @import("../app.zig"); const coral = @import("coral"); @@ -25,6 +27,408 @@ const Builtin = enum { vec3, }; +const Compiler = struct { + chunk: *Self, + env: *kym.RuntimeEnv, + + fn compile_argument(self: *const Compiler, environment: *const tree.Environment, initial_argument: ?*const Expr) kym.RuntimeError!u8 { + // TODO: Exceeding 255 arguments will make the VM crash. + var maybe_argument = initial_argument; + var argument_count = @as(u8, 0); + + while (maybe_argument) |argument| { + try self.compile_expression(environment, argument, null); + + maybe_argument = argument.next; + argument_count += 1; + } + + return argument_count; + } + + fn compile_expression(self: *const Compiler, environment: *const tree.Environment, expression: *const Expr, name: ?[]const coral.io.Byte) kym.RuntimeError!void { + const number_format = coral.utf8.DecimalFormat{ + .delimiter = "_", + .positive_prefix = .none, + }; + + switch (expression.kind) { + .nil_literal => try self.chunk.write(expression.line, .push_nil), + .true_literal => try self.chunk.write(expression.line, .push_true), + .false_literal => try self.chunk.write(expression.line, .push_false), + + .number_literal => |literal| { + for (literal) |codepoint| { + if (codepoint == '.') { + return self.chunk.write(expression.line, .{ + .push_const = try self.declare_float(number_format.parse(literal, kym.Float) orelse unreachable), + }); + } + } + + try self.chunk.write(expression.line, .{ + .push_const = try self.declare_fixed(number_format.parse(literal, kym.Fixed) orelse unreachable), + }); + }, + + .string_literal => |literal| { + try self.chunk.write(expression.line, .{.push_const = try self.declare_string(literal)}); + }, + + .symbol_literal => |literal| { + try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(literal)}); + }, + + .table_construct => |table_construct| { + var table_entry = table_construct.entry; + var field_count = @as(u32, 0); + + while (table_entry) |entry| : (table_entry = entry.next) { + try self.compile_expression(environment, entry, null); + + if (entry.kind != .key_value) { + try self.chunk.write(expression.line, .push_top); + } + + field_count += 1; + } + + try self.chunk.write(expression.line, .{.push_table = field_count}); + }, + + .key_value => |key_value| { + try self.compile_expression(environment, key_value.value, null); + try self.compile_expression(environment, key_value.key, null); + }, + + .lambda_construct => |lambda_construct| { + var chunk = try Self.make(self.env, name orelse "", lambda_construct.environment); + + errdefer chunk.free(self.env); + + if (lambda_construct.environment.capture_count == 0) { + try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)}); + } else { + const lambda_captures = lambda_construct.environment.get_captures(); + var index = lambda_captures.len; + + while (index != 0) { + index -= 1; + + try self.chunk.write(expression.line, switch (lambda_captures[index]) { + .declaration_index => |declaration_index| .{.push_local = declaration_index}, + .capture_index => |capture_index| .{.push_binding = capture_index}, + }); + } + + try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)}); + try self.chunk.write(expression.line, .{.bind = lambda_construct.environment.capture_count}); + } + }, + + .binary_op => |binary_op| { + try self.compile_expression(environment, binary_op.lhs_operand, null); + try self.compile_expression(environment, binary_op.rhs_operand, null); + + try self.chunk.write(expression.line, switch (binary_op.operation) { + .addition => .add, + .subtraction => .sub, + .multiplication => .mul, + .divsion => .div, + .greater_equals_comparison => .cge, + .greater_than_comparison => .cgt, + .equals_comparison => .eql, + .less_than_comparison => .clt, + .less_equals_comparison => .cle, + }); + }, + + .unary_op => |unary_op| { + try self.compile_expression(environment, unary_op.operand, null); + + try self.chunk.write(expression.line, switch (unary_op.operation) { + .boolean_negation => .not, + .numeric_negation => .neg, + }); + }, + + .invoke => |invoke| { + const argument_count = try self.compile_argument(environment, invoke.argument); + + try self.compile_expression(environment, invoke.object, null); + try self.chunk.write(expression.line, .{.call = argument_count}); + }, + + .group => |group| try self.compile_expression(environment, group, null), + .import_builtin => try self.chunk.write(expression.line, .{.push_builtin = .import}), + .print_builtin => try self.chunk.write(expression.line, .{.push_builtin = .print}), + .vec2_builtin => try self.chunk.write(expression.line, .{.push_builtin = .vec2}), + .vec3_builtin => try self.chunk.write(expression.line, .{.push_builtin = .vec3}), + + .declaration_get => |declaration_get| { + if (get_local_index(environment, declaration_get.declaration)) |index| { + return self.chunk.write(expression.line, .{.push_local = index}); + } + + if (try self.get_binding_index(environment, declaration_get.declaration)) |index| { + try self.chunk.write(expression.line, .{.push_binding = index}); + + if (is_declaration_boxed(declaration_get.declaration)) { + try self.chunk.write(expression.line, .get_box); + } + + return; + } + + return self.env.raise(error.IllegalState, "local out of scope", .{}); + }, + + .declaration_set => |declaration_set| { + if (get_local_index(environment, declaration_set.declaration)) |index| { + try self.compile_expression(environment, declaration_set.assign, null); + + return self.chunk.write(expression.line, .{.set_local = index}); + } + + if (try self.get_binding_index(environment, declaration_set.declaration)) |index| { + try self.chunk.write(expression.line, .{.push_binding = index}); + try self.compile_expression(environment, declaration_set.assign, null); + + if (is_declaration_boxed(declaration_set.declaration)) { + try self.chunk.write(expression.line, .set_box); + } + + return; + } + + return self.env.raise(error.IllegalState, "local out of scope", .{}); + }, + + .field_get => |field_get| { + try self.compile_expression(environment, field_get.object, null); + try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(field_get.identifier)}); + try self.chunk.write(expression.line, .get_dynamic); + }, + + .field_set => |field_set| { + try self.compile_expression(environment, field_set.object, null); + try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(field_set.identifier)}); + try self.compile_expression(environment, field_set.assign, null); + try self.chunk.write(expression.line, .set_dynamic); + }, + + .subscript_get => |subscript_get| { + try self.compile_expression(environment, subscript_get.object, null); + try self.compile_expression(environment, subscript_get.index, null); + try self.chunk.write(expression.line, .get_dynamic); + }, + + .subscript_set => |subscript_set| { + try self.compile_expression(environment, subscript_set.object, null); + try self.compile_expression(environment, subscript_set.index, null); + try self.compile_expression(environment, subscript_set.assign, null); + try self.chunk.write(expression.line, .set_dynamic); + }, + } + } + + pub fn compile_environment(self: *const Compiler, environment: *const tree.Environment) kym.RuntimeError!void { + if (environment.statement) |statement| { + const last_statement = try self.compile_statement(environment, statement); + + if (last_statement.kind != .@"return") { + try self.chunk.write(last_statement.line, .push_nil); + } + } + } + + fn compile_statement(self: *const Compiler, environment: *const tree.Environment, initial_statement: *const Stmt) kym.RuntimeError!*const Stmt { + var current_statement = initial_statement; + + while (true) { + switch (current_statement.kind) { + .@"return" => |@"return"| { + if (@"return".returned_expression) |expression| { + try self.compile_expression(environment, expression, null); + } else { + try self.chunk.write(current_statement.line, .push_nil); + } + + // TODO: Omit ret calls at ends of chunk. + try self.chunk.write(current_statement.line, .ret); + }, + + .@"while" => |@"while"| { + try self.compile_expression(environment, @"while".loop_expression, null); + try self.chunk.write(current_statement.line, .{.jf = 0}); + + const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1)); + + _ = try self.compile_statement(environment, @"while".loop); + self.chunk.opcodes.values[origin_index].jf = @intCast(self.chunk.opcodes.values.len - 1); + + try self.compile_expression(environment, @"while".loop_expression, null); + try self.chunk.write(current_statement.line, .{.jt = origin_index}); + }, + + .@"if" => |@"if"| { + try self.compile_expression(environment, @"if".then_expression, null); + try self.chunk.write(current_statement.line, .{.jf = 0}); + + const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1)); + + _ = try self.compile_statement(environment, @"if".@"then"); + self.chunk.opcodes.values[origin_index].jf = @intCast(self.chunk.opcodes.values.len - 1); + + if (@"if".@"else") |@"else"| { + _ = try self.compile_statement(environment, @"else"); + } + }, + + .declare => |declare| { + try self.compile_expression(environment, declare.initial_expression, declare.declaration.identifier); + + if (is_declaration_boxed(declare.declaration)) { + try self.chunk.write(current_statement.line, .push_boxed); + } + }, + + .top_expression => |top_expression| { + try self.compile_expression(environment, top_expression, null); + + if (top_expression.kind == .invoke) { + try self.chunk.write(current_statement.line, .pop); + } + }, + } + + current_statement = current_statement.next orelse return current_statement; + } + } + + const constants_max = @as(usize, coral.math.max_int(@typeInfo(u16).Int)); + + fn declare_chunk(self: *const Compiler, chunk: Self) kym.RuntimeError!u16 { + if (self.chunk.constants.values.len == coral.math.max_int(@typeInfo(u16).Int)) { + return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ + .max = @as(usize, coral.math.max_int(@typeInfo(u16).Int)), + }); + } + + const constant = try self.env.new_dynamic(coral.io.bytes_of(&chunk), typeinfo); + + errdefer self.env.discard(constant); + + try self.chunk.constants.push_one(constant); + + return @intCast(self.chunk.constants.values.len - 1); + } + + fn declare_fixed(self: *const Compiler, fixed: kym.Fixed) kym.RuntimeError!u16 { + if (self.chunk.constants.values.len == constants_max) { + return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ + .max = constants_max, + }); + } + + const constant = try self.env.new_fixed(fixed); + + errdefer self.env.discard(constant); + + try self.chunk.constants.push_one(constant); + + return @intCast(self.chunk.constants.values.len - 1); + } + + fn declare_float(self: *const Compiler, float: kym.Float) kym.RuntimeError!u16 { + if (self.chunk.constants.values.len == constants_max) { + return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ + .max = constants_max, + }); + } + + const constant = try self.env.new_float(float); + + errdefer self.env.discard(constant); + + try self.chunk.constants.push_one(constant); + + return @intCast(self.chunk.constants.values.len - 1); + } + + fn declare_string(self: *const Compiler, string: []const coral.io.Byte) kym.RuntimeError!u16 { + if (self.chunk.constants.values.len == constants_max) { + return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ + .max = constants_max, + }); + } + + const constant = try self.env.new_string(string); + + errdefer self.env.discard(constant); + + try self.chunk.constants.push_one(constant); + + return @intCast(self.chunk.constants.values.len - 1); + } + + fn declare_symbol(self: *const Compiler, symbol: []const coral.io.Byte) kym.RuntimeError!u16 { + if (self.chunk.constants.values.len == constants_max) { + return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ + .max = constants_max, + }); + } + + const constant = try self.env.new_symbol(symbol); + + errdefer self.env.discard(constant); + + try self.chunk.constants.push_one(constant); + + return @intCast(self.chunk.constants.values.len - 1); + } + + fn get_binding_index(self: *const Compiler, environment: *const tree.Environment, declaration: *const tree.Declaration) kym.RuntimeError!?u8 { + var binding_index = @as(u8, 0); + + while (binding_index < environment.capture_count) : (binding_index += 1) { + var capture = &environment.captures[binding_index]; + var target_environment = environment.enclosing orelse return null; + + while (capture.* == .capture_index) { + capture = &target_environment.captures[capture.capture_index]; + target_environment = target_environment.enclosing orelse return null; + } + + try kym.assert(self.env, capture.* == .declaration_index); + + if (&target_environment.declarations[capture.declaration_index] == declaration) { + return binding_index; + } + } + + return null; + } + + fn get_local_index(environment: *const tree.Environment, declaration: *const tree.Declaration) ?u8 { + var remaining = environment.declaration_count; + + while (remaining != 0) { + remaining -= 1; + + if (&environment.declarations[remaining] == declaration) { + return remaining; + } + } + + return null; + } + + fn is_declaration_boxed(declaration: *const tree.Declaration) bool { + return declaration.is.captured and !declaration.is.readonly; + } +}; + const ConstList = coral.list.Stack(*kym.RuntimeRef); const LineList = coral.list.Stack(u32); diff --git a/source/ona/kym/Compiler.zig b/source/ona/kym/Compiler.zig deleted file mode 100644 index 771331f..0000000 --- a/source/ona/kym/Compiler.zig +++ /dev/null @@ -1,413 +0,0 @@ -const Chunk = @import("./Chunk.zig"); - -const Expr = @import("./Expr.zig"); - -const Stmt = @import("./Stmt.zig"); - -const coral = @import("coral"); - -const kym = @import("../kym.zig"); - -const tree = @import("./tree.zig"); - -chunk: *Chunk, -env: *kym.RuntimeEnv, - -const Self = @This(); - -fn compile_argument(self: Self, environment: *const tree.Environment, initial_argument: ?*const Expr) kym.RuntimeError!u8 { - // TODO: Exceeding 255 arguments will make the VM crash. - var maybe_argument = initial_argument; - var argument_count = @as(u8, 0); - - while (maybe_argument) |argument| { - try self.compile_expression(environment, argument, null); - - maybe_argument = argument.next; - argument_count += 1; - } - - return argument_count; -} - -fn compile_expression(self: Self, environment: *const tree.Environment, expression: *const Expr, name: ?[]const coral.io.Byte) kym.RuntimeError!void { - const number_format = coral.utf8.DecimalFormat{ - .delimiter = "_", - .positive_prefix = .none, - }; - - switch (expression.kind) { - .nil_literal => try self.chunk.write(expression.line, .push_nil), - .true_literal => try self.chunk.write(expression.line, .push_true), - .false_literal => try self.chunk.write(expression.line, .push_false), - - .number_literal => |literal| { - for (literal) |codepoint| { - if (codepoint == '.') { - return self.chunk.write(expression.line, .{ - .push_const = try self.declare_float(number_format.parse(literal, kym.Float) orelse unreachable), - }); - } - } - - try self.chunk.write(expression.line, .{ - .push_const = try self.declare_fixed(number_format.parse(literal, kym.Fixed) orelse unreachable), - }); - }, - - .string_literal => |literal| { - try self.chunk.write(expression.line, .{.push_const = try self.declare_string(literal)}); - }, - - .symbol_literal => |literal| { - try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(literal)}); - }, - - .table_construct => |table_construct| { - var table_entry = table_construct.entry; - var field_count = @as(u32, 0); - - while (table_entry) |entry| : (table_entry = entry.next) { - try self.compile_expression(environment, entry, null); - - if (entry.kind != .key_value) { - try self.chunk.write(expression.line, .push_top); - } - - field_count += 1; - } - - try self.chunk.write(expression.line, .{.push_table = field_count}); - }, - - .key_value => |key_value| { - try self.compile_expression(environment, key_value.value, null); - try self.compile_expression(environment, key_value.key, null); - }, - - .lambda_construct => |lambda_construct| { - var chunk = try Chunk.make(self.env, name orelse "", lambda_construct.environment); - - errdefer chunk.free(self.env); - - if (lambda_construct.environment.capture_count == 0) { - try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)}); - } else { - const lambda_captures = lambda_construct.environment.get_captures(); - var index = lambda_captures.len; - - while (index != 0) { - index -= 1; - - try self.chunk.write(expression.line, switch (lambda_captures[index]) { - .declaration_index => |declaration_index| .{.push_local = declaration_index}, - .capture_index => |capture_index| .{.push_binding = capture_index}, - }); - } - - try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)}); - try self.chunk.write(expression.line, .{.bind = lambda_construct.environment.capture_count}); - } - }, - - .binary_op => |binary_op| { - try self.compile_expression(environment, binary_op.lhs_operand, null); - try self.compile_expression(environment, binary_op.rhs_operand, null); - - try self.chunk.write(expression.line, switch (binary_op.operation) { - .addition => .add, - .subtraction => .sub, - .multiplication => .mul, - .divsion => .div, - .greater_equals_comparison => .cge, - .greater_than_comparison => .cgt, - .equals_comparison => .eql, - .less_than_comparison => .clt, - .less_equals_comparison => .cle, - }); - }, - - .unary_op => |unary_op| { - try self.compile_expression(environment, unary_op.operand, null); - - try self.chunk.write(expression.line, switch (unary_op.operation) { - .boolean_negation => .not, - .numeric_negation => .neg, - }); - }, - - .invoke => |invoke| { - const argument_count = try self.compile_argument(environment, invoke.argument); - - try self.compile_expression(environment, invoke.object, null); - try self.chunk.write(expression.line, .{.call = argument_count}); - }, - - .group => |group| try self.compile_expression(environment, group, null), - .import_builtin => try self.chunk.write(expression.line, .{.push_builtin = .import}), - .print_builtin => try self.chunk.write(expression.line, .{.push_builtin = .print}), - .vec2_builtin => try self.chunk.write(expression.line, .{.push_builtin = .vec2}), - .vec3_builtin => try self.chunk.write(expression.line, .{.push_builtin = .vec3}), - - .declaration_get => |declaration_get| { - if (get_local_index(environment, declaration_get.declaration)) |index| { - return self.chunk.write(expression.line, .{.push_local = index}); - } - - if (try self.get_binding_index(environment, declaration_get.declaration)) |index| { - try self.chunk.write(expression.line, .{.push_binding = index}); - - if (is_declaration_boxed(declaration_get.declaration)) { - try self.chunk.write(expression.line, .get_box); - } - - return; - } - - return self.env.raise(error.IllegalState, "local out of scope", .{}); - }, - - .declaration_set => |declaration_set| { - if (get_local_index(environment, declaration_set.declaration)) |index| { - try self.compile_expression(environment, declaration_set.assign, null); - - return self.chunk.write(expression.line, .{.set_local = index}); - } - - if (try self.get_binding_index(environment, declaration_set.declaration)) |index| { - try self.chunk.write(expression.line, .{.push_binding = index}); - try self.compile_expression(environment, declaration_set.assign, null); - - if (is_declaration_boxed(declaration_set.declaration)) { - try self.chunk.write(expression.line, .set_box); - } - - return; - } - - return self.env.raise(error.IllegalState, "local out of scope", .{}); - }, - - .field_get => |field_get| { - try self.compile_expression(environment, field_get.object, null); - try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(field_get.identifier)}); - try self.chunk.write(expression.line, .get_dynamic); - }, - - .field_set => |field_set| { - try self.compile_expression(environment, field_set.object, null); - try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(field_set.identifier)}); - try self.compile_expression(environment, field_set.assign, null); - try self.chunk.write(expression.line, .set_dynamic); - }, - - .subscript_get => |subscript_get| { - try self.compile_expression(environment, subscript_get.object, null); - try self.compile_expression(environment, subscript_get.index, null); - try self.chunk.write(expression.line, .get_dynamic); - }, - - .subscript_set => |subscript_set| { - try self.compile_expression(environment, subscript_set.object, null); - try self.compile_expression(environment, subscript_set.index, null); - try self.compile_expression(environment, subscript_set.assign, null); - try self.chunk.write(expression.line, .set_dynamic); - }, - } -} - -pub fn compile_environment(self: Self, environment: *const tree.Environment) kym.RuntimeError!void { - if (environment.statement) |statement| { - const last_statement = try self.compile_statement(environment, statement); - - if (last_statement.kind != .@"return") { - try self.chunk.write(last_statement.line, .push_nil); - } - } -} - -fn compile_statement(self: Self, environment: *const tree.Environment, initial_statement: *const Stmt) kym.RuntimeError!*const Stmt { - var current_statement = initial_statement; - - while (true) { - switch (current_statement.kind) { - .@"return" => |@"return"| { - if (@"return".returned_expression) |expression| { - try self.compile_expression(environment, expression, null); - } else { - try self.chunk.write(current_statement.line, .push_nil); - } - - // TODO: Omit ret calls at ends of chunk. - try self.chunk.write(current_statement.line, .ret); - }, - - .@"while" => |@"while"| { - try self.compile_expression(environment, @"while".loop_expression, null); - try self.chunk.write(current_statement.line, .{.jf = 0}); - - const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1)); - - _ = try self.compile_statement(environment, @"while".loop); - self.chunk.opcodes.values[origin_index].jf = @intCast(self.chunk.opcodes.values.len - 1); - - try self.compile_expression(environment, @"while".loop_expression, null); - try self.chunk.write(current_statement.line, .{.jt = origin_index}); - }, - - .@"if" => |@"if"| { - try self.compile_expression(environment, @"if".then_expression, null); - try self.chunk.write(current_statement.line, .{.jf = 0}); - - const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1)); - - _ = try self.compile_statement(environment, @"if".@"then"); - self.chunk.opcodes.values[origin_index].jf = @intCast(self.chunk.opcodes.values.len - 1); - - if (@"if".@"else") |@"else"| { - _ = try self.compile_statement(environment, @"else"); - } - }, - - .declare => |declare| { - try self.compile_expression(environment, declare.initial_expression, declare.declaration.identifier); - - if (is_declaration_boxed(declare.declaration)) { - try self.chunk.write(current_statement.line, .push_boxed); - } - }, - - .top_expression => |top_expression| { - try self.compile_expression(environment, top_expression, null); - - if (top_expression.kind == .invoke) { - try self.chunk.write(current_statement.line, .pop); - } - }, - } - - current_statement = current_statement.next orelse return current_statement; - } -} - -const constants_max = @as(usize, coral.math.max_int(@typeInfo(u16).Int)); - -fn declare_chunk(self: Self, chunk: Chunk) kym.RuntimeError!u16 { - if (self.chunk.constants.values.len == coral.math.max_int(@typeInfo(u16).Int)) { - return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ - .max = @as(usize, coral.math.max_int(@typeInfo(u16).Int)), - }); - } - - const constant = try self.env.new_dynamic(coral.io.bytes_of(&chunk), Chunk.typeinfo); - - errdefer self.env.discard(constant); - - try self.chunk.constants.push_one(constant); - - return @intCast(self.chunk.constants.values.len - 1); -} - -fn declare_fixed(self: Self, fixed: kym.Fixed) kym.RuntimeError!u16 { - if (self.chunk.constants.values.len == constants_max) { - return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ - .max = constants_max, - }); - } - - const constant = try self.env.new_fixed(fixed); - - errdefer self.env.discard(constant); - - try self.chunk.constants.push_one(constant); - - return @intCast(self.chunk.constants.values.len - 1); -} - -fn declare_float(self: Self, float: kym.Float) kym.RuntimeError!u16 { - if (self.chunk.constants.values.len == constants_max) { - return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ - .max = constants_max, - }); - } - - const constant = try self.env.new_float(float); - - errdefer self.env.discard(constant); - - try self.chunk.constants.push_one(constant); - - return @intCast(self.chunk.constants.values.len - 1); -} - -fn declare_string(self: Self, string: []const coral.io.Byte) kym.RuntimeError!u16 { - if (self.chunk.constants.values.len == constants_max) { - return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ - .max = constants_max, - }); - } - - const constant = try self.env.new_string(string); - - errdefer self.env.discard(constant); - - try self.chunk.constants.push_one(constant); - - return @intCast(self.chunk.constants.values.len - 1); -} - -fn declare_symbol(self: Self, symbol: []const coral.io.Byte) kym.RuntimeError!u16 { - if (self.chunk.constants.values.len == constants_max) { - return self.env.raise(error.BadSyntax, "chunks cannot contain more than {max} constants", .{ - .max = constants_max, - }); - } - - const constant = try self.env.new_symbol(symbol); - - errdefer self.env.discard(constant); - - try self.chunk.constants.push_one(constant); - - return @intCast(self.chunk.constants.values.len - 1); -} - -pub fn get_binding_index(self: *const Self, environment: *const tree.Environment, declaration: *const tree.Declaration) kym.RuntimeError!?u8 { - var binding_index = @as(u8, 0); - - while (binding_index < environment.capture_count) : (binding_index += 1) { - var capture = &environment.captures[binding_index]; - var target_environment = environment.enclosing orelse return null; - - while (capture.* == .capture_index) { - capture = &target_environment.captures[capture.capture_index]; - target_environment = target_environment.enclosing orelse return null; - } - - try kym.assert(self.env, capture.* == .declaration_index); - - if (&target_environment.declarations[capture.declaration_index] == declaration) { - return binding_index; - } - } - - return null; -} - -pub fn get_local_index(environment: *const tree.Environment, declaration: *const tree.Declaration) ?u8 { - var remaining = environment.declaration_count; - - while (remaining != 0) { - remaining -= 1; - - if (&environment.declarations[remaining] == declaration) { - return remaining; - } - } - - return null; -} - -fn is_declaration_boxed(declaration: *const tree.Declaration) bool { - return declaration.is.captured and !declaration.is.readonly; -}