|
| 1 | +const std = @import("std"); |
| 2 | +const base = @import("base"); |
| 3 | +const ModuleEnv = @import("ModuleEnv.zig"); |
| 4 | +const CIR = @import("CIR.zig"); |
| 5 | + |
| 6 | +/// Replace all e_anno_only expressions in a hosted module with e_hosted_lambda operations. |
| 7 | +/// This transforms standalone annotations into hosted lambda operations that will be |
| 8 | +/// provided by the host application at runtime. |
| 9 | +/// Returns a list of new def indices created. |
| 10 | +pub fn replaceAnnoOnlyWithHosted(env: *ModuleEnv) !std.ArrayList(CIR.Def.Idx) { |
| 11 | + const gpa = env.gpa; |
| 12 | + var new_def_indices = std.ArrayList(CIR.Def.Idx).empty; |
| 13 | + |
| 14 | + // Ensure types array has entries for all existing nodes |
| 15 | + // This is necessary because varFrom(node_idx) assumes type_var index == node index |
| 16 | + const current_nodes = env.store.nodes.len(); |
| 17 | + const current_types = env.types.len(); |
| 18 | + if (current_types < current_nodes) { |
| 19 | + // Fill the gap with fresh type variables |
| 20 | + var i: u64 = current_types; |
| 21 | + while (i < current_nodes) : (i += 1) { |
| 22 | + _ = env.types.fresh() catch unreachable; |
| 23 | + } |
| 24 | + } |
| 25 | + |
| 26 | + // Iterate through all defs and replace ALL anno-only defs with hosted implementations |
| 27 | + const all_defs = env.store.sliceDefs(env.all_defs); |
| 28 | + for (all_defs) |def_idx| { |
| 29 | + const def = env.store.getDef(def_idx); |
| 30 | + const expr = env.store.getExpr(def.expr); |
| 31 | + |
| 32 | + // Check if this is an anno-only def (e_anno_only expression) |
| 33 | + if (expr == .e_anno_only and def.annotation != null) { |
| 34 | + // Get the identifier from the pattern |
| 35 | + const pattern = env.store.getPattern(def.pattern); |
| 36 | + if (pattern == .assign) { |
| 37 | + const ident = pattern.assign.ident; |
| 38 | + |
| 39 | + // Create a dummy parameter pattern for the lambda |
| 40 | + // Use the identifier "_arg" for the parameter |
| 41 | + const arg_ident = env.common.findIdent("_arg") orelse try env.common.insertIdent(gpa, base.Ident.for_text("_arg")); |
| 42 | + const arg_pattern_idx = try env.addPattern(.{ .assign = .{ .ident = arg_ident } }, base.Region.zero()); |
| 43 | + |
| 44 | + // Create a pattern span containing just this one parameter |
| 45 | + const patterns_start = env.store.scratchTop("patterns"); |
| 46 | + try env.store.scratch.?.patterns.append(arg_pattern_idx); |
| 47 | + const args_span = CIR.Pattern.Span{ .span = .{ .start = @intCast(patterns_start), .len = 1 } }; |
| 48 | + |
| 49 | + // Create an e_runtime_error body that crashes when the function is called in the interpreter |
| 50 | + const error_msg_lit = try env.insertString("Hosted functions cannot be called in the interpreter"); |
| 51 | + const diagnostic_idx = try env.addDiagnostic(.{ .not_implemented = .{ |
| 52 | + .feature = error_msg_lit, |
| 53 | + .region = base.Region.zero(), |
| 54 | + } }); |
| 55 | + const body_idx = try env.addExpr(.{ .e_runtime_error = .{ .diagnostic = diagnostic_idx } }, base.Region.zero()); |
| 56 | + |
| 57 | + // Create e_hosted_lambda expression |
| 58 | + const expr_idx = try env.addExpr(.{ .e_hosted_lambda = .{ |
| 59 | + .symbol_name = ident, |
| 60 | + .args = args_span, |
| 61 | + .body = body_idx, |
| 62 | + } }, base.Region.zero()); |
| 63 | + |
| 64 | + // Now replace the e_anno_only expression with the e_hosted_lambda |
| 65 | + // We need to modify the def's expr field to point to our new expression |
| 66 | + // CIR.Def.Idx and Node.Idx have the same underlying representation |
| 67 | + const def_node_idx = @as(@TypeOf(env.store.nodes).Idx, @enumFromInt(@intFromEnum(def_idx))); |
| 68 | + var def_node = env.store.nodes.get(def_node_idx); |
| 69 | + def_node.data_2 = @intFromEnum(expr_idx); |
| 70 | + env.store.nodes.set(def_node_idx, def_node); |
| 71 | + |
| 72 | + // Track this replaced def index |
| 73 | + try new_def_indices.append(gpa, def_idx); |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + return new_def_indices; |
| 79 | +} |
0 commit comments