build options #compiler
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
#import "modules/std.sx";
|
#import "modules/std.sx";
|
||||||
|
#import "modules/math";
|
||||||
|
|
||||||
Vec :: struct($N: u32, $T:Type) {
|
Vec :: struct($N: u32, $T:Type) {
|
||||||
// <N x T> (LLVM Vector)
|
// <N x T> (LLVM Vector)
|
||||||
|
|||||||
@@ -6,14 +6,8 @@ ARCH : Architecture = .unknown;
|
|||||||
POINTER_SIZE : s64 = 8;
|
POINTER_SIZE : s64 = 8;
|
||||||
|
|
||||||
BuildOptions :: struct {
|
BuildOptions :: struct {
|
||||||
add_link_flag :: (self: BuildOptions, flag: [:0]u8) {
|
add_link_flag :: (self: BuildOptions, flag: [:0]u8) #compiler;
|
||||||
// Compiler builtin — intercepted at compile time
|
set_output_path :: (self: BuildOptions, path: [:0]u8) #compiler;
|
||||||
}
|
|
||||||
set_output_path :: (self: BuildOptions, path: [:0]u8) {
|
|
||||||
// Compiler builtin — intercepted at compile time
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build_options :: () -> BuildOptions {
|
build_options :: () -> BuildOptions #compiler;
|
||||||
return BuildOptions.{};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ pub const Node = struct {
|
|||||||
undef_literal: void,
|
undef_literal: void,
|
||||||
inferred_type: void,
|
inferred_type: void,
|
||||||
builtin_expr: void,
|
builtin_expr: void,
|
||||||
|
compiler_expr: void,
|
||||||
foreign_expr: ForeignExpr,
|
foreign_expr: ForeignExpr,
|
||||||
library_decl: LibraryDecl,
|
library_decl: LibraryDecl,
|
||||||
function_type_expr: FunctionTypeExpr,
|
function_type_expr: FunctionTypeExpr,
|
||||||
|
|||||||
101
src/ir/compiler_hooks.zig
Normal file
101
src/ir/compiler_hooks.zig
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const interp_mod = @import("interp.zig");
|
||||||
|
const Value = interp_mod.Value;
|
||||||
|
const Interpreter = interp_mod.Interpreter;
|
||||||
|
|
||||||
|
// ── BuildConfig ─────────────────────────────────────────────────────────
|
||||||
|
// Mutable build configuration accumulated by #run blocks via #compiler methods.
|
||||||
|
|
||||||
|
pub const BuildConfig = struct {
|
||||||
|
link_flags: std.ArrayList([]const u8) = .empty,
|
||||||
|
output_path: ?[]const u8 = null,
|
||||||
|
|
||||||
|
pub fn deinit(self: *BuildConfig, alloc: Allocator) void {
|
||||||
|
self.link_flags.deinit(alloc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── Hook system ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
pub const HookError = error{
|
||||||
|
CannotEvalComptime,
|
||||||
|
TypeError,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Hook function signature. Receives the interpreter (for heap/string access),
|
||||||
|
/// resolved argument values, and the mutable build config.
|
||||||
|
pub const HookFn = *const fn (
|
||||||
|
interp: *const Interpreter,
|
||||||
|
args: []const Value,
|
||||||
|
bc: *BuildConfig,
|
||||||
|
alloc: Allocator,
|
||||||
|
) HookError!Value;
|
||||||
|
|
||||||
|
pub const Registry = struct {
|
||||||
|
hooks: std.StringHashMap(HookFn),
|
||||||
|
|
||||||
|
pub fn init(alloc: Allocator) Registry {
|
||||||
|
return .{ .hooks = std.StringHashMap(HookFn).init(alloc) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Registry) void {
|
||||||
|
self.hooks.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *const Registry, name: []const u8) ?HookFn {
|
||||||
|
return self.hooks.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register all built-in compiler hooks.
|
||||||
|
pub fn registerDefaults(self: *Registry) void {
|
||||||
|
self.hooks.put("build_options", &hookBuildOptions) catch {};
|
||||||
|
self.hooks.put("BuildOptions.add_link_flag", &hookAddLinkFlag) catch {};
|
||||||
|
self.hooks.put("BuildOptions.set_output_path", &hookSetOutputPath) catch {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── build_options() hook ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
fn hookBuildOptions(
|
||||||
|
_: *const Interpreter,
|
||||||
|
_: []const Value,
|
||||||
|
_: *BuildConfig,
|
||||||
|
_: Allocator,
|
||||||
|
) HookError!Value {
|
||||||
|
// build_options() returns a sentinel value; the real work happens
|
||||||
|
// when methods like add_link_flag/set_output_path are called on it.
|
||||||
|
return .void_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── BuildOptions hooks ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
fn hookAddLinkFlag(
|
||||||
|
interp: *const Interpreter,
|
||||||
|
args: []const Value,
|
||||||
|
bc: *BuildConfig,
|
||||||
|
alloc: Allocator,
|
||||||
|
) HookError!Value {
|
||||||
|
// args: [self (BuildOptions value), flag_string]
|
||||||
|
if (args.len < 2) return .void_val;
|
||||||
|
const str_val = args[1];
|
||||||
|
if (str_val.asString(interp)) |s| {
|
||||||
|
bc.link_flags.append(alloc, alloc.dupe(u8, s) catch return error.CannotEvalComptime) catch return error.CannotEvalComptime;
|
||||||
|
}
|
||||||
|
return .void_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hookSetOutputPath(
|
||||||
|
interp: *const Interpreter,
|
||||||
|
args: []const Value,
|
||||||
|
bc: *BuildConfig,
|
||||||
|
alloc: Allocator,
|
||||||
|
) HookError!Value {
|
||||||
|
// args: [self (BuildOptions value), path_string]
|
||||||
|
if (args.len < 2) return .void_val;
|
||||||
|
const str_val = args[1];
|
||||||
|
if (str_val.asString(interp)) |s| {
|
||||||
|
bc.output_path = alloc.dupe(u8, s) catch return error.CannotEvalComptime;
|
||||||
|
}
|
||||||
|
return .void_val;
|
||||||
|
}
|
||||||
@@ -1454,6 +1454,10 @@ pub const LLVMEmitter = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.compiler_call => {
|
||||||
|
// Compiler hooks are comptime-only; if one reaches emission, produce undef
|
||||||
|
self.mapRef(c.LLVMGetUndef(self.toLLVMType(instruction.ty)));
|
||||||
|
},
|
||||||
.call_closure => |call_op| {
|
.call_closure => |call_op| {
|
||||||
// Closure: { fn_ptr, env } — extract fn_ptr, prepend env as first arg
|
// Closure: { fn_ptr, env } — extract fn_ptr, prepend env as first arg
|
||||||
const closure = self.resolveRef(call_op.callee);
|
const closure = self.resolveRef(call_op.callee);
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ pub const Op = union(enum) {
|
|||||||
call_indirect: CallIndirect,
|
call_indirect: CallIndirect,
|
||||||
call_closure: CallIndirect,
|
call_closure: CallIndirect,
|
||||||
call_builtin: BuiltinCall,
|
call_builtin: BuiltinCall,
|
||||||
|
compiler_call: CompilerCall,
|
||||||
|
|
||||||
// ── Protocol dispatch ───────────────────────────────────────────
|
// ── Protocol dispatch ───────────────────────────────────────────
|
||||||
protocol_call_dynamic: ProtocolCall, // vtable/inline dispatch
|
protocol_call_dynamic: ProtocolCall, // vtable/inline dispatch
|
||||||
@@ -302,9 +303,11 @@ pub const BuiltinId = enum(u16) {
|
|||||||
type_of,
|
type_of,
|
||||||
alloc,
|
alloc,
|
||||||
dealloc,
|
dealloc,
|
||||||
build_options,
|
};
|
||||||
build_options_add_link_flag,
|
|
||||||
build_options_set_output_path,
|
pub const CompilerCall = struct {
|
||||||
|
name: u32, // StringPool id for qualified name (e.g. "BuildOptions.add_link_flag")
|
||||||
|
args: []const Ref,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ProtocolCall = struct {
|
pub const ProtocolCall = struct {
|
||||||
|
|||||||
@@ -106,17 +106,8 @@ pub const InterpError = error{
|
|||||||
Unreachable,
|
Unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── BuildConfig ─────────────────────────────────────────────────────────
|
const compiler_hooks = @import("compiler_hooks.zig");
|
||||||
// Mutable build configuration accumulated by #run blocks via BuildOptions methods.
|
pub const BuildConfig = compiler_hooks.BuildConfig;
|
||||||
|
|
||||||
pub const BuildConfig = struct {
|
|
||||||
link_flags: std.ArrayList([]const u8) = .empty,
|
|
||||||
output_path: ?[]const u8 = null,
|
|
||||||
|
|
||||||
pub fn deinit(self: *BuildConfig, alloc: Allocator) void {
|
|
||||||
self.link_flags.deinit(alloc);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ── Interpreter ─────────────────────────────────────────────────────────
|
// ── Interpreter ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -136,13 +127,19 @@ pub const Interpreter = struct {
|
|||||||
// Mutable build configuration — set by LLVMEmitter, written by #run blocks
|
// Mutable build configuration — set by LLVMEmitter, written by #run blocks
|
||||||
build_config: ?*BuildConfig = null,
|
build_config: ?*BuildConfig = null,
|
||||||
|
|
||||||
|
// Compiler hook registry for #compiler methods
|
||||||
|
hooks: compiler_hooks.Registry,
|
||||||
|
|
||||||
pub fn init(module: *const Module, alloc: Allocator) Interpreter {
|
pub fn init(module: *const Module, alloc: Allocator) Interpreter {
|
||||||
|
var hooks = compiler_hooks.Registry.init(alloc);
|
||||||
|
hooks.registerDefaults();
|
||||||
return .{
|
return .{
|
||||||
.module = module,
|
.module = module,
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.output = std.ArrayList(u8).empty,
|
.output = std.ArrayList(u8).empty,
|
||||||
.heap = std.ArrayList([]u8).empty,
|
.heap = std.ArrayList([]u8).empty,
|
||||||
.global_values = std.AutoHashMap(u32, Value).init(alloc),
|
.global_values = std.AutoHashMap(u32, Value).init(alloc),
|
||||||
|
.hooks = hooks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +151,7 @@ pub const Interpreter = struct {
|
|||||||
self.heap.deinit(self.alloc);
|
self.heap.deinit(self.alloc);
|
||||||
self.output.deinit(self.alloc);
|
self.output.deinit(self.alloc);
|
||||||
self.global_values.deinit();
|
self.global_values.deinit();
|
||||||
|
self.hooks.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Heap operations ────────────────────────────────────────────
|
// ── Heap operations ────────────────────────────────────────────
|
||||||
@@ -618,6 +616,25 @@ pub const Interpreter = struct {
|
|||||||
return self.execBuiltin(bi, frame, instruction.ty);
|
return self.execBuiltin(bi, frame, instruction.ty);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ── Compiler hook calls (#compiler methods) ────────
|
||||||
|
.compiler_call => |cc| {
|
||||||
|
const name = self.module.types.getString(@enumFromInt(cc.name));
|
||||||
|
if (self.hooks.get(name)) |hook| {
|
||||||
|
// Resolve args from Ref to Value
|
||||||
|
var resolved_args = std.ArrayList(Value).empty;
|
||||||
|
defer resolved_args.deinit(self.alloc);
|
||||||
|
for (cc.args) |arg| {
|
||||||
|
resolved_args.append(self.alloc, frame.getRef(arg)) catch return error.CannotEvalComptime;
|
||||||
|
}
|
||||||
|
if (self.build_config) |bc| {
|
||||||
|
const result = hook(self, resolved_args.items, bc, self.alloc) catch return error.CannotEvalComptime;
|
||||||
|
return .{ .value = result };
|
||||||
|
}
|
||||||
|
return .{ .value = .void_val };
|
||||||
|
}
|
||||||
|
return error.CannotEvalComptime;
|
||||||
|
},
|
||||||
|
|
||||||
// ── Struct GEP (field pointer) ─────────────────────
|
// ── Struct GEP (field pointer) ─────────────────────
|
||||||
.struct_gep => |fa| {
|
.struct_gep => |fa| {
|
||||||
const base = frame.getRef(fa.base);
|
const base = frame.getRef(fa.base);
|
||||||
@@ -1257,30 +1274,6 @@ pub const Interpreter = struct {
|
|||||||
const f = val.asFloat() orelse return error.TypeError;
|
const f = val.asFloat() orelse return error.TypeError;
|
||||||
return .{ .value = .{ .float = @floor(f) } };
|
return .{ .value = .{ .float = @floor(f) } };
|
||||||
},
|
},
|
||||||
.build_options => {
|
|
||||||
// Returns a void sentinel — the "handle" to BuildConfig
|
|
||||||
return .{ .value = .void_val };
|
|
||||||
},
|
|
||||||
.build_options_add_link_flag => {
|
|
||||||
// args: [opts_handle, flag_string]
|
|
||||||
const str_val = frame.getRef(bi.args[1]);
|
|
||||||
if (str_val.asString(self)) |s| {
|
|
||||||
if (self.build_config) |bc| {
|
|
||||||
bc.link_flags.append(self.alloc, self.alloc.dupe(u8, s) catch return error.CannotEvalComptime) catch return error.CannotEvalComptime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return .{ .value = .void_val };
|
|
||||||
},
|
|
||||||
.build_options_set_output_path => {
|
|
||||||
// args: [opts_handle, path_string]
|
|
||||||
const str_val = frame.getRef(bi.args[1]);
|
|
||||||
if (str_val.asString(self)) |s| {
|
|
||||||
if (self.build_config) |bc| {
|
|
||||||
bc.output_path = self.alloc.dupe(u8, s) catch return error.CannotEvalComptime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return .{ .value = .void_val };
|
|
||||||
},
|
|
||||||
.cast, .type_of, .alloc, .dealloc => {
|
.cast, .type_of, .alloc, .dealloc => {
|
||||||
return error.CannotEvalComptime;
|
return error.CannotEvalComptime;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ pub const Interpreter = interp.Interpreter;
|
|||||||
pub const Value = interp.Value;
|
pub const Value = interp.Value;
|
||||||
pub const Lowering = lower.Lowering;
|
pub const Lowering = lower.Lowering;
|
||||||
|
|
||||||
|
pub const compiler_hooks = @import("compiler_hooks.zig");
|
||||||
pub const emit_llvm = @import("emit_llvm.zig");
|
pub const emit_llvm = @import("emit_llvm.zig");
|
||||||
pub const LLVMEmitter = emit_llvm.LLVMEmitter;
|
pub const LLVMEmitter = emit_llvm.LLVMEmitter;
|
||||||
|
|
||||||
|
|||||||
@@ -534,7 +534,7 @@ pub const Lowering = struct {
|
|||||||
// No AST? (builtins, foreign functions, or imported functions not in this file)
|
// No AST? (builtins, foreign functions, or imported functions not in this file)
|
||||||
const fd = self.fn_ast_map.get(name) orelse return;
|
const fd = self.fn_ast_map.get(name) orelse return;
|
||||||
// Check builtin/foreign/generic — these stay as extern stubs
|
// Check builtin/foreign/generic — these stay as extern stubs
|
||||||
if (fd.body.data == .builtin_expr or fd.body.data == .foreign_expr) return;
|
if (fd.body.data == .builtin_expr or fd.body.data == .foreign_expr or fd.body.data == .compiler_expr) return;
|
||||||
if (fd.type_params.len > 0) return; // generics handled by monomorphization (Step 3.13)
|
if (fd.type_params.len > 0) return; // generics handled by monomorphization (Step 3.13)
|
||||||
|
|
||||||
// Defer functions with type-category matches until all types are registered.
|
// Defer functions with type-category matches until all types are registered.
|
||||||
@@ -685,7 +685,7 @@ pub const Lowering = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the function body is a builtin or foreign declaration (no body needed)
|
// Check if the function body is a builtin or foreign declaration (no body needed)
|
||||||
if (fd.body.data == .builtin_expr or fd.body.data == .foreign_expr) {
|
if (fd.body.data == .builtin_expr or fd.body.data == .foreign_expr or fd.body.data == .compiler_expr) {
|
||||||
// Already declared by scanDecls/declareFunction (which handles #foreign renames)
|
// Already declared by scanDecls/declareFunction (which handles #foreign renames)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3707,6 +3707,14 @@ pub const Lowering = struct {
|
|||||||
return self.lowerGenericCall(fd, func_name, c, args.items);
|
return self.lowerGenericCall(fd, func_name, c, args.items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check for #compiler free functions
|
||||||
|
if (self.fn_ast_map.get(func_name)) |fd_check| {
|
||||||
|
if (fd_check.body.data == .compiler_expr) {
|
||||||
|
const ret_ty = if (fd_check.return_type) |rt| type_bridge.resolveAstType(rt, &self.module.types) else TypeId.void;
|
||||||
|
return self.builder.compilerCall(func_name, args.items, ret_ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Look up declared/extern function — try lazy lowering if not yet lowered
|
// Look up declared/extern function — try lazy lowering if not yet lowered
|
||||||
{
|
{
|
||||||
// First attempt: function may already be declared (from scanDecls)
|
// First attempt: function may already be declared (from scanDecls)
|
||||||
@@ -3960,18 +3968,16 @@ pub const Lowering = struct {
|
|||||||
// Try to resolve the method by struct type name
|
// Try to resolve the method by struct type name
|
||||||
const struct_name = self.getStructTypeName(obj_ty);
|
const struct_name = self.getStructTypeName(obj_ty);
|
||||||
if (struct_name) |sname| {
|
if (struct_name) |sname| {
|
||||||
// Intercept BuildOptions compiler builtins
|
|
||||||
if (std.mem.eql(u8, sname, "BuildOptions")) {
|
|
||||||
if (std.mem.eql(u8, fa.field, "add_link_flag")) {
|
|
||||||
return self.builder.callBuiltin(.build_options_add_link_flag, method_args.items, .void);
|
|
||||||
} else if (std.mem.eql(u8, fa.field, "set_output_path")) {
|
|
||||||
return self.builder.callBuiltin(.build_options_set_output_path, method_args.items, .void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try direct qualified name: StructName.method
|
// Try direct qualified name: StructName.method
|
||||||
const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ sname, fa.field }) catch fa.field;
|
const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ sname, fa.field }) catch fa.field;
|
||||||
|
|
||||||
|
// Generic #compiler method dispatch
|
||||||
|
if (self.fn_ast_map.get(qualified)) |method_fd| {
|
||||||
|
if (method_fd.body.data == .compiler_expr) {
|
||||||
|
return self.builder.compilerCall(qualified, method_args.items, .void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for generic struct template method
|
// Check for generic struct template method
|
||||||
if (self.struct_instance_template.get(sname)) |tmpl_name| {
|
if (self.struct_instance_template.get(sname)) |tmpl_name| {
|
||||||
// This is an instantiated generic struct — look up template method
|
// This is an instantiated generic struct — look up template method
|
||||||
@@ -7595,13 +7601,14 @@ pub const Lowering = struct {
|
|||||||
const oi = self.module.types.get(obj_ty);
|
const oi = self.module.types.get(obj_ty);
|
||||||
if (oi == .@"struct") {
|
if (oi == .@"struct") {
|
||||||
const struct_name = self.module.types.getString(oi.@"struct".name);
|
const struct_name = self.module.types.getString(oi.@"struct".name);
|
||||||
// Intercept BuildOptions compiler builtins
|
const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ struct_name, cfa.field }) catch cfa.field;
|
||||||
if (std.mem.eql(u8, struct_name, "BuildOptions")) {
|
// Generic #compiler method dispatch — return type from declaration
|
||||||
if (std.mem.eql(u8, cfa.field, "add_link_flag") or std.mem.eql(u8, cfa.field, "set_output_path")) {
|
if (self.fn_ast_map.get(qualified)) |method_fd| {
|
||||||
|
if (method_fd.body.data == .compiler_expr) {
|
||||||
|
if (method_fd.return_type) |rt| return type_bridge.resolveAstType(rt, &self.module.types);
|
||||||
return .void;
|
return .void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ struct_name, cfa.field }) catch cfa.field;
|
|
||||||
if (self.resolveFuncByName(qualified)) |fid| {
|
if (self.resolveFuncByName(qualified)) |fid| {
|
||||||
return self.module.functions.items[@intFromEnum(fid)].ret;
|
return self.module.functions.items[@intFromEnum(fid)].ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -362,6 +362,12 @@ pub const Builder = struct {
|
|||||||
return self.emit(.{ .call_builtin = .{ .builtin = builtin, .args = owned } }, ret_ty);
|
return self.emit(.{ .call_builtin = .{ .builtin = builtin, .args = owned } }, ret_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compilerCall(self: *Builder, name: []const u8, args: []const Ref, ret_ty: TypeId) Ref {
|
||||||
|
const name_id = self.module.types.strings.intern(self.module.alloc, name);
|
||||||
|
const owned = self.module.alloc.dupe(Ref, args) catch unreachable;
|
||||||
|
return self.emit(.{ .compiler_call = .{ .name = @intFromEnum(name_id), .args = owned } }, ret_ty);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Protocol ────────────────────────────────────────────────────
|
// ── Protocol ────────────────────────────────────────────────────
|
||||||
|
|
||||||
pub fn protocolCallDynamic(self: *Builder, receiver: Ref, method_index: u32, args: []const Ref, ret_ty: TypeId) Ref {
|
pub fn protocolCallDynamic(self: *Builder, receiver: Ref, method_index: u32, args: []const Ref, ret_ty: TypeId) Ref {
|
||||||
|
|||||||
@@ -316,6 +316,12 @@ fn printInst(instruction: *const Inst, ref_idx: u32, tt: *const TypeTable, write
|
|||||||
try writeArgs(c.args, writer);
|
try writeArgs(c.args, writer);
|
||||||
try writer.writeAll(") : ");
|
try writer.writeAll(") : ");
|
||||||
},
|
},
|
||||||
|
.compiler_call => |cc| {
|
||||||
|
const name = tt.getString(@enumFromInt(cc.name));
|
||||||
|
try writer.print("compiler_call \"{s}\"(", .{name});
|
||||||
|
try writeArgs(cc.args, writer);
|
||||||
|
try writer.writeAll(") : ");
|
||||||
|
},
|
||||||
|
|
||||||
// ── Protocol ────────────────────────────────────────────
|
// ── Protocol ────────────────────────────────────────────
|
||||||
.protocol_call_dynamic => |c| {
|
.protocol_call_dynamic => |c| {
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ pub const Lexer = struct {
|
|||||||
.{ "#insert", Tag.hash_insert },
|
.{ "#insert", Tag.hash_insert },
|
||||||
.{ "#run", Tag.hash_run },
|
.{ "#run", Tag.hash_run },
|
||||||
.{ "#builtin", Tag.hash_builtin },
|
.{ "#builtin", Tag.hash_builtin },
|
||||||
|
.{ "#compiler", Tag.hash_compiler },
|
||||||
.{ "#foreign", Tag.hash_foreign },
|
.{ "#foreign", Tag.hash_foreign },
|
||||||
.{ "#library", Tag.hash_library },
|
.{ "#library", Tag.hash_library },
|
||||||
.{ "#using", Tag.hash_using },
|
.{ "#using", Tag.hash_using },
|
||||||
|
|||||||
@@ -1482,6 +1482,7 @@ pub const Server = struct {
|
|||||||
.hash_import,
|
.hash_import,
|
||||||
.hash_insert,
|
.hash_insert,
|
||||||
.hash_builtin,
|
.hash_builtin,
|
||||||
|
.hash_compiler,
|
||||||
.hash_foreign,
|
.hash_foreign,
|
||||||
.hash_library,
|
.hash_library,
|
||||||
.hash_using,
|
.hash_using,
|
||||||
|
|||||||
@@ -1215,13 +1215,18 @@ pub const Parser = struct {
|
|||||||
return_type = try self.parseTypeExpr();
|
return_type = try self.parseTypeExpr();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Body: block `{ ... }`, arrow `=> expr;`, #builtin, or #foreign marker
|
// Body: block `{ ... }`, arrow `=> expr;`, #builtin, #compiler, or #foreign marker
|
||||||
var is_arrow = false;
|
var is_arrow = false;
|
||||||
const body = if (self.current.tag == .hash_builtin) blk: {
|
const body = if (self.current.tag == .hash_builtin) blk: {
|
||||||
const bi_start = self.current.loc.start;
|
const bi_start = self.current.loc.start;
|
||||||
self.advance();
|
self.advance();
|
||||||
try self.expect(.semicolon);
|
try self.expect(.semicolon);
|
||||||
break :blk try self.createNode(bi_start, .{ .builtin_expr = {} });
|
break :blk try self.createNode(bi_start, .{ .builtin_expr = {} });
|
||||||
|
} else if (self.current.tag == .hash_compiler) blk: {
|
||||||
|
const ci_start = self.current.loc.start;
|
||||||
|
self.advance();
|
||||||
|
try self.expect(.semicolon);
|
||||||
|
break :blk try self.createNode(ci_start, .{ .compiler_expr = {} });
|
||||||
} else if (self.current.tag == .hash_foreign) blk: {
|
} else if (self.current.tag == .hash_foreign) blk: {
|
||||||
const fi_start = self.current.loc.start;
|
const fi_start = self.current.loc.start;
|
||||||
self.advance();
|
self.advance();
|
||||||
@@ -2351,7 +2356,7 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
fn isFunctionDef(self: *Parser) bool {
|
fn isFunctionDef(self: *Parser) bool {
|
||||||
const tag = self.peekPastParens() orelse return false;
|
const tag = self.peekPastParens() orelse return false;
|
||||||
return tag == .l_brace or tag == .arrow or tag == .hash_builtin or tag == .hash_foreign or tag == .fat_arrow;
|
return tag == .l_brace or tag == .arrow or tag == .hash_builtin or tag == .hash_compiler or tag == .hash_foreign or tag == .fat_arrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isAssignOp(self: *const Parser) bool {
|
fn isAssignOp(self: *const Parser) bool {
|
||||||
|
|||||||
@@ -862,6 +862,7 @@ pub const Analyzer = struct {
|
|||||||
.undef_literal,
|
.undef_literal,
|
||||||
.inferred_type,
|
.inferred_type,
|
||||||
.builtin_expr,
|
.builtin_expr,
|
||||||
|
.compiler_expr,
|
||||||
.foreign_expr,
|
.foreign_expr,
|
||||||
.library_decl,
|
.library_decl,
|
||||||
.function_type_expr,
|
.function_type_expr,
|
||||||
@@ -1264,6 +1265,7 @@ pub fn findNodeAtOffset(node: *Node, offset: u32) ?*Node {
|
|||||||
.undef_literal,
|
.undef_literal,
|
||||||
.inferred_type,
|
.inferred_type,
|
||||||
.builtin_expr,
|
.builtin_expr,
|
||||||
|
.compiler_expr,
|
||||||
.foreign_expr,
|
.foreign_expr,
|
||||||
.library_decl,
|
.library_decl,
|
||||||
.function_type_expr,
|
.function_type_expr,
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ pub const Tag = enum {
|
|||||||
hash_import, // #import
|
hash_import, // #import
|
||||||
hash_insert, // #insert
|
hash_insert, // #insert
|
||||||
hash_builtin, // #builtin
|
hash_builtin, // #builtin
|
||||||
|
hash_compiler, // #compiler
|
||||||
hash_foreign, // #foreign
|
hash_foreign, // #foreign
|
||||||
hash_library, // #library
|
hash_library, // #library
|
||||||
hash_using, // #using
|
hash_using, // #using
|
||||||
|
|||||||
Reference in New Issue
Block a user