diff --git a/src/ast.zig b/src/ast.zig index fced71b..18fa70e 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -124,7 +124,7 @@ pub const CallingConvention = enum { default, c }; /// Linkage modifier written in the postfix slot after `callconv(...)`: /// `name :: (sig) -> Ret [callconv(.x)] [extern | export] [;|{…}];` -/// `extern` = import (external linkage, C ABI, no sx ctx — `#foreign`'s role); +/// `extern` = import (external linkage, C ABI, no sx ctx — `extern`'s role); /// `export` = define + expose (body + external linkage + C ABI + no ctx). /// Both imply `callconv(.c)`. Variants carry a trailing `_` to dodge the Zig /// keywords. `.none` = no linkage modifier (the ordinary sx-internal decl). @@ -143,20 +143,20 @@ pub const FnDecl = struct { /// Parsed in Phase 0.1; not consumed by the fn-decl path until Phase 1. extern_export: ExternExportModifier = .none, /// Optional library reference + symbol-name override for an `extern`/`export` - /// function, mirroring `#foreign LIB "csym"` (foreign_lib/foreign_name). Both + /// function, the optional library + symbol-name override. Both /// optional: `extern` alone resolves the sx name against the default-linked /// libs; `extern LIB` names the source library; `extern "csym"` renames the /// symbol. Required for `extern` to be a behavior-equivalent superset of - /// `#foreign` (Gate A→B) — the migration of 466 `#foreign` uses across 6 libs + /// `extern` (Gate A→B) — the migration of 466 `extern` uses across 6 libs /// must preserve each symbol's library. Parsed/consumed in Phase 1.2. extern_lib: ?[]const u8 = null, extern_name: ?[]const u8 = null, /// Span of the function's name token, for the reserved-type-name decl - /// diagnostic. Synthesized decls (e.g. `#import c` foreign + /// diagnostic. Synthesized decls (e.g. `#import c` extern /// functions, lowering-time objc/protocol method synthesis) leave it zero. name_span: Span = .{ .start = 0, .end = 0 }, /// True when the function NAME was written as a backtick raw identifier - /// (`` `i2 :: … ``) or synthesized by a `#import c` foreign decl. A raw + /// (`` `i2 :: … ``) or synthesized by a `#import c` extern decl. A raw /// name is exempt from the reserved-type-name binding check. /// Every PARSER fn_decl is built through `parseFnDecl`, whose `name_is_raw` /// is a REQUIRED parameter, so a parser site cannot drop it; the default @@ -185,7 +185,7 @@ pub const Param = struct { /// parameter, lowering substitutes this expression in its place. default_expr: ?*Node = null, /// True when the param name was written as a backtick raw identifier - /// (`` `i2 ``) or synthesized by a `#import c` foreign decl. A raw name is + /// (`` `i2 ``) or synthesized by a `#import c` extern decl. A raw name is /// exempt from the reserved-type-name binding check. is_raw: bool = false, }; @@ -866,7 +866,7 @@ pub const RuntimeFieldDecl = struct { name: []const u8, field_type: *Node, // type_expr node /// True iff the declaration carries a `#property[(...)]` directive - /// (M2.2). For foreign classes, that means synthesize getter/setter + /// (M2.2). For runtime classes, that means synthesize getter/setter /// dispatch through `objc_msgSend`; for sx-defined classes it adds /// runtime-introspectable property metadata + ARC-aware setter /// emission (Month 4 wires the latter). diff --git a/src/backend/llvm/ops.zig b/src/backend/llvm/ops.zig index 62281e4..5e5a179 100644 --- a/src/backend/llvm/ops.zig +++ b/src/backend/llvm/ops.zig @@ -485,7 +485,7 @@ pub const Ops = struct { pub fn emitObjcMsgSend(self: Ops, instruction: *const Inst, msg: ObjcMsgSend) void { const msg_send = self.e.getObjcMsgSendValue(); // Detect the sret case: >16 B non-HFA struct return. - // Same predicate as the plain-foreign-call path so the + // Same predicate as the plain-extern-call path so the // two arms stay in lockstep. const raw_ret_ty = self.e.toLLVMType(instruction.ty); const uses_sret = self.e.needsByval(instruction.ty, raw_ret_ty); @@ -516,7 +516,7 @@ pub const Ops = struct { call_args[sret_off + 1] = self.e.coerceArg(self.e.resolveRef(msg.sel), self.e.cached_ptr); // additional args take their IR types, with ABI // coercion applied so structs / strings decay the - // same way they do for any C foreign call. + // same way they do for any C extern call. for (msg.args, 0..) |arg_ref, i| { const raw_ty = self.e.argIRTypeOrFail(arg_ref); const raw_llvm = self.e.toLLVMType(raw_ty); diff --git a/src/c_import.zig b/src/c_import.zig index dba7c7b..f2f3424 100644 --- a/src/c_import.zig +++ b/src/c_import.zig @@ -309,7 +309,7 @@ pub fn processCImport( // Native C compilation (compile to .o, not LLVM module) // --------------------------------------------------------------------------- -// ── #foreign ref validation ─────────────────────────────────────────── +// ── extern ref validation ─────────────────────────────────────────── fn collectExternRefTargets(valid: *std.StringHashMap(void), decls: []const *Node) !void { for (decls) |d| { @@ -349,7 +349,7 @@ fn checkExternRefs(valid: *const std.StringHashMap(void), decls: []const *Node, } } -/// Validate every `#foreign ` in the merged program: the ref must +/// Validate every `extern ` in the merged program: the ref must /// name a `#library` constant or a NAMED `#import c` unit. Refs are /// author-side module-local names, but modules merge flat or /// namespaced into one tree, so existence is checked program-wide. diff --git a/src/core.zig b/src/core.zig index 62d8712..21f347a 100644 --- a/src/core.zig +++ b/src/core.zig @@ -299,7 +299,7 @@ pub const Compilation = struct { pub fn lowerToIR(self: *Compilation) !ir.Module { const root = self.resolved_root orelse self.root orelse return ir.Module.init(self.allocator); - // Every `#foreign ` must name a #library constant or a named + // Every `extern ` must name a #library constant or a named // `#import c` unit — a typo'd ref otherwise resolves silently // through whatever image happens to carry the symbol. try c_import.validateExternRefs(self.allocator, root, &self.diagnostics); diff --git a/src/imports.zig b/src/imports.zig index 5ac891c..47b8b96 100644 --- a/src/imports.zig +++ b/src/imports.zig @@ -366,8 +366,8 @@ pub const ResolvedModule = struct { /// types/aliases and supports same-name value consts (step E5). Everything /// else keeps the first-wins name-merge: FUNCTIONS (the shadowed /// author stays reachable via its qualified name / SelectedFunc), and crucially - /// `var_decl`s, including a `#foreign` extern global declared in two files - /// (e.g. `__stdinp : *void #foreign;`) that MUST resolve to the ONE libSystem + /// `var_decl`s, including a `extern` extern global declared in two files + /// (e.g. `__stdinp : *void extern;`) that MUST resolve to the ONE libSystem /// symbol, not split into a duplicate `__stdinp.1`. fn isPerSourceDecl(decl: *const Node) bool { return switch (decl.data) { @@ -852,7 +852,7 @@ fn stampStructMethodSources(sd: ast.StructDecl, file_path: []const u8) void { } /// Stamp the defining module path onto every bodied method of an sx-defined -/// foreign class, so the method's sx body lowers in the class's own module. +/// runtime class, so the method's sx body lowers in the class's own module. fn stampRuntimeClassMethodSources(fcd: ast.RuntimeClassDecl, file_path: []const u8) void { for (fcd.members) |m| { if (m == .method) { diff --git a/src/ir/calls.test.zig b/src/ir/calls.test.zig index 8526a66..d95f3a1 100644 --- a/src/ir/calls.test.zig +++ b/src/ir/calls.test.zig @@ -7,7 +7,7 @@ // 2. The `CallPlan` object built by `CallResolver.plan` — its selected // kind / target / variant and the receiver / `__sx_ctx` / default-arg // properties, across every call form pinned by A3.2 sub-step 1 -// (direct / UFCS / protocol / closure / fn-pointer / foreign / enum / +// (direct / UFCS / protocol / closure / fn-pointer / extern / enum / // namespace). `resultType` is just `plan(c).return_type`, so these also // lock the typing the regression suite relies on. @@ -346,7 +346,7 @@ test "plan: struct (UFCS) method via #compiler dispatch + prepends receiver" { try std.testing.expect(p.prepends_receiver); } -test "plan: foreign-class instance vs static dispatch" { +test "plan: runtime-class instance vs static dispatch" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const alloc = arena.allocator(); diff --git a/src/ir/calls.zig b/src/ir/calls.zig index 3e8afaa..6c3afe6 100644 --- a/src/ir/calls.zig +++ b/src/ir/calls.zig @@ -92,13 +92,13 @@ pub const CallPlan = struct { /// `Lowering.inferExprType`'s call arm. Discovers the IR type a call /// expression evaluates to — across builtins / reflection builtins, generic /// and plain free functions (lowered or lazy via `fn_ast_map`), closure / -/// function-typed locals, protocol dispatch, foreign-class instance/static +/// function-typed locals, protocol dispatch, runtime-class instance/static /// methods, struct (UFCS) methods, qualified namespace calls, and /// enum/tagged-union construction. /// /// A `*Lowering` facade (Principle 5, like `ExprTyper` / `PackResolver`): call /// typing reads live lexical-scope / target-type state and the function / -/// foreign-class / protocol resolver helpers, so it borrows `*Lowering` rather +/// runtime-class / protocol resolver helpers, so it borrows `*Lowering` rather /// than re-threading every field. pub const CallResolver = struct { l: *Lowering, @@ -159,7 +159,7 @@ pub const CallResolver = struct { // Plain bare same-name flat collision (R5 §C): route through the ONE // author producer `selectedFreeAuthor` so `plan` types the call as the // SAME author the lowering call-path binds — they can no longer - // disagree. A generic / foreign / builtin author is not + // disagree. A generic / extern / builtin author is not // plain-free so the producer returns `.none`; `.ambiguous` / `.none` // fall through to the first-wins path below, byte-for-byte. switch (self.selectedFreeAuthor(c)) { @@ -386,7 +386,7 @@ pub const CallResolver = struct { }; } } - // Type.variant(args) — qualified construction; foreign static; or a + // Type.variant(args) — qualified construction; runtime static; or a // qualified namespace function. Reached for namespace / type // prefixes (and inert for value receivers handled above). const type_name = switch (cfa.object.data) { @@ -506,7 +506,7 @@ pub const CallResolver = struct { /// name is never a same-name free-fn collision → `.none`. /// - field-access callee with a VALUE receiver: a free-function UFCS /// (`recv.fn(args)`). A namespace / type prefix receiver → `.none`. The - /// verdict over-selects a struct-method / protocol / foreign call whose + /// verdict over-selects a struct-method / protocol / extern call whose /// field happens to name a free fn, but those dispatch BEFORE the free-fn /// UFCS path in both `plan` and `lowerCall`, so the verdict is consumed only /// when the call truly is a free-fn UFCS. diff --git a/src/ir/emit_llvm.test.zig b/src/ir/emit_llvm.test.zig index b3ca92b..d2a322a 100644 --- a/src/ir/emit_llvm.test.zig +++ b/src/ir/emit_llvm.test.zig @@ -355,7 +355,7 @@ test "emit: type conversion toLLVMType" { // ── A7.1 scaffolding: ABI param coercion ──────────────────────────── // Lock the C-ABI struct-coercion buckets (abiCoerceParamType / needsByval), -// which feed callconv(.c) / #foreign signatures, before they move to +// which feed callconv(.c) / #extern signatures, before they move to // src/backend/llvm/abi.zig in A7.1 sub-step 2. const llvm = @import("../llvm_api.zig"); @@ -1103,7 +1103,7 @@ test "emit: ERR E3.0 — no DWARF without a debug context (unit-test default)" { // JNI CallMethod / non-virtual / constructor). A ref it cannot resolve is // a codegen invariant violation; it must surface the dedicated `.unresolved` // tripwire sentinel (which `toLLVMType` hard-panics on) rather than the old -// silent `.void` default that would emit a void-typed foreign-call argument. +// silent `.void` default that would emit a void-typed extern-call argument. test "emit: argIRTypeOrFail surfaces .unresolved for an unresolvable FFI arg ref (issue 0074)" { const alloc = std.testing.allocator; var module = Module.init(alloc); @@ -1136,7 +1136,7 @@ test "emit: argIRTypeOrFail surfaces .unresolved for an unresolvable FFI arg ref // Fail-before: the old `getRefIRType(arg) orelse .void` would silently // yield `.void` here — a real, load-bearing type that downstream ABI - // coercion treats as a legitimate (void-typed) foreign argument. + // coercion treats as a legitimate (void-typed) extern argument. try std.testing.expectEqual(TypeId.void, emitter.getRefIRType(bogus) orelse TypeId.void); // Pass-after: the helper returns the dedicated `.unresolved` sentinel, diff --git a/src/ir/emit_llvm.zig b/src/ir/emit_llvm.zig index 5acf8c6..3d270c6 100644 --- a/src/ir/emit_llvm.zig +++ b/src/ir/emit_llvm.zig @@ -35,7 +35,7 @@ const Value = interp_mod.Value; // The vendored error-trace ring buffer (library/vendors/sx_trace_runtime/sx_trace.c) // is linked into the compiler. Comptime `#run` evaluation pushes frames to it via -// foreign `sx_trace_push` calls; after a `#run` we read it here to render the +// extern `sx_trace_push` calls; after a `#run` we read it here to render the // return trace for an escaping comptime error (E5.2). extern fn sx_trace_len() u32; extern fn sx_trace_frame_at(i: u32) u64; @@ -371,7 +371,7 @@ pub const LLVMEmitter = struct { self.ffiCtors().emitObjcSelectorInit(); // Pass 2.5b: Emit Obj-C class-pair registration constructor for - // sx-defined classes (M1.2 A.4+). Runs BEFORE the foreign + // sx-defined classes (M1.2 A.4+). Runs BEFORE the runtime // class-cache populator (2.5c) so a sx-defined class is already // registered with the Obj-C runtime by the time // `objc_getClass(\"SxFoo\")` runs to populate the Phase 3.1 @@ -888,7 +888,7 @@ pub const LLVMEmitter = struct { const llvm_global = c.LLVMAddGlobal(self.llvm_module, llvm_ty, name_z.ptr); - // Extern globals (` : #foreign;`) resolve at link time + // Extern globals (` : extern;`) resolve at link time // to a libSystem / framework symbol — no initializer, default linkage. if (global.is_extern) { c.LLVMSetLinkage(llvm_global, c.LLVMExternalLinkage); @@ -1242,7 +1242,7 @@ pub const LLVMEmitter = struct { // main always returns i32 at the LLVM level (JIT expects it) const raw_ret_ty = self.toLLVMType(func.ret); const needs_c_abi = func.is_extern or func.call_conv == .c; - // A foreign `-> string` / `-> ?string` receives ONE `char *` from C; + // An extern `-> string` / `-> ?string` receives ONE `char *` from C; // the fat sx value is synthesized at the call site (emitCall's // cstrReturnToSx). Never sret — the C callee knows nothing about an // out-pointer. @@ -1259,7 +1259,7 @@ pub const LLVMEmitter = struct { else if (needs_c_abi) self.abiCoerceParamTypeEx(func.ret, raw_ret_ty, func.is_extern) else raw_ret_ty; - // Build parameter types — apply C ABI coercion for foreign/callconv(.c) functions. + // Build parameter types — apply C ABI coercion for extern/callconv(.c) functions. // When uses_sret, prepend the sret pointer at index 0. const sret_offset: usize = if (uses_sret) 1 else 0; const param_count: c_uint = @intCast(func.params.len + sret_offset); @@ -1322,7 +1322,7 @@ pub const LLVMEmitter = struct { // Apple ARM64 ABI for >16B non-HFA composites: pass by reference // via a pointer in the next int register (NOT via LLVM's `byval` // attribute, which lowers the struct on the stack — incompatible - // with what `clang` emits and what foreign C callees expect). + // with what `clang` emits and what extern C callees expect). // abiCoerceParamType returned `ptr` for these slots, so the formal // param IS a plain pointer; the prologue loads the struct back. @@ -2267,7 +2267,7 @@ pub const LLVMEmitter = struct { return .none; } - /// Build the sx-level value for a foreign call that returned a `char *`: + /// Build the sx-level value for a extern call that returned a `char *`: /// `{ptr, strlen(ptr)}` for `string` (NULL → `{null, 0}`), wrapped in /// `{string, i1}` with `has = ptr != null` for `?string`. The strlen call /// is branch-guarded — `select` would evaluate `strlen(NULL)`. @@ -2452,12 +2452,12 @@ pub const LLVMEmitter = struct { return null; } - /// Resolve the IR type of a foreign-call argument ref. Every FFI arg ref is + /// Resolve the IR type of a extern-call argument ref. Every FFI arg ref is /// a real function param or block instruction result, so a `null` here is a /// codegen invariant violation, not a recoverable case: return the dedicated /// `.unresolved` sentinel — never `.void`/`.i64` — so the failure cannot be /// mistaken for a real type and trips `toLLVMType`'s hard tripwire at the call - /// site instead of silently emitting a void-typed foreign argument. + /// site instead of silently emitting a void-typed extern argument. pub fn argIRTypeOrFail(self: *LLVMEmitter, arg_ref: Ref) TypeId { return self.getRefIRType(arg_ref) orelse .unresolved; } @@ -2519,7 +2519,7 @@ pub const LLVMEmitter = struct { return self.typeLowering().toLLVMType(ty); } - // ── C ABI coercion for foreign functions ────────────────────────── + // ── C ABI coercion for extern functions ────────────────────────── // The coercion logic lives in `backend/llvm/abi.zig` (`AbiLowering`); // these stay the facade entry points (callers in signature/call emission + // the block-trampoline path use abiCoerceParamTypeEx directly). diff --git a/src/ir/ffi_objc.zig b/src/ir/ffi_objc.zig index 5d0d2b4..d9c773b 100644 --- a/src/ir/ffi_objc.zig +++ b/src/ir/ffi_objc.zig @@ -172,7 +172,7 @@ pub const ObjcLowering = struct { .isize => try out.append(self.l.alloc, 'q'), .usize => try out.append(self.l.alloc, 'Q'), .pointer => |p| { - // Pointer to a foreign Obj-C class (or sx-defined #objc_class) + // Pointer to a runtime Obj-C class (or sx-defined #objc_class) // encodes as `@`. Anything else falls to `^v` — generic // pointer; the runtime treats it as opaque. const pointee_info = self.l.module.types.get(p.pointee); @@ -378,7 +378,7 @@ pub const ObjcLowering = struct { const pointee = self.l.module.types.get(field_ty).pointer.pointee; // `*void` is NOT considered an object pointer — ambiguous. if (pointee == .void) break :blk false; - // `*T` where T is a foreign-class struct (Obj-C class). + // `*T` where T is a runtime-class struct (Obj-C class). if (pointee.isBuiltin()) break :blk false; const pointee_info = self.l.module.types.get(pointee); if (pointee_info != .@"struct") break :blk false; diff --git a/src/ir/host_ffi.zig b/src/ir/host_ffi.zig index 2be92ef..255df42 100644 --- a/src/ir/host_ffi.zig +++ b/src/ir/host_ffi.zig @@ -77,7 +77,7 @@ pub fn callVoidRet(symbol: *anyopaque, args: []const usize) !void { } // ── Variadic cdecl dispatch ───────────────────────────────────────── -// For foreign functions declared with `args: ..T` (C-variadic, e.g. +// For extern functions declared with `args: ..T` (C-variadic, e.g. // libc `open(path, flags, ...)`). The trailing args must be passed // through the C-variadic ABI — arm64 places them on the stack rather // than in argument registers. Calling a variadic function as if it diff --git a/src/ir/inst.zig b/src/ir/inst.zig index 4f96291..1ec9e33 100644 --- a/src/ir/inst.zig +++ b/src/ir/inst.zig @@ -498,7 +498,7 @@ pub const Function = struct { linkage: Linkage = .internal, call_conv: CallingConvention = .default, source_file: ?[]const u8 = null, - /// Variadic tail at the IR signature level. Only `#foreign` decls reach + /// Variadic tail at the IR signature level. Only `extern` decls reach /// IR with this set — sx-side `..T` params are slice-packed before /// lowering, so anything that survives is the C calling convention's /// `...`. emit_llvm passes `is_var_arg=1` to `LLVMFunctionType`; call diff --git a/src/ir/interp.zig b/src/ir/interp.zig index 6aea99a..a75ecba 100644 --- a/src/ir/interp.zig +++ b/src/ir/interp.zig @@ -174,7 +174,7 @@ pub const Interpreter = struct { max_call_depth: u32 = 256, /// Active sx call-frame chain (oldest→newest), maintained across `call` for /// `trace.print_interpreter_frames()` (ERR E4.1). Only sx-bodied frames are - /// tracked — foreign calls return before the frame is pushed. + /// tracked — extern calls return before the frame is pushed. call_chain: std.ArrayList(FuncId) = .empty, /// File → source text (the diagnostics' import_sources). Set by the host @@ -218,7 +218,7 @@ pub const Interpreter = struct { return error.CannotEvalComptime; } - /// Like `bailDetail` but returns a `TypeError` — for foreign-arg + /// Like `bailDetail` but returns a `TypeError` — for extern-arg /// marshalling sites that previously erased the reason. fn typeErrorDetail(comptime msg: []const u8) InterpError { if (last_bail_detail == null) last_bail_detail = msg; @@ -258,7 +258,7 @@ pub const Interpreter = struct { /// Write `val` to the raw host address `addr` using exactly the /// number of bytes declared by `val_ty`. Used when the - /// protocol-dispatch chain bottoms out at a foreign-libc-malloc + /// protocol-dispatch chain bottoms out at a extern-libc-malloc /// pointer and sx code stores through it. Comptime safety is the /// caller's responsibility — wild writes will fault. fn storeAtRawPtr(self: *Interpreter, addr: i64, val: Value, val_ty: @import("types.zig").TypeId) InterpError!void { @@ -414,7 +414,7 @@ pub const Interpreter = struct { .heap_ptr => |hp| blk: { // `heapSlice` returns the slice already advanced by `hp.offset`, // so its `.ptr` IS the offset address. Adding `hp.offset` again - // double-counts and lands the foreign call past the buffer end. + // double-counts and lands the extern call past the buffer end. _ = self.heapSlice(hp) orelse return error.TypeError; break :blk @intFromPtr(self.heap.items[hp.id].ptr) + hp.offset; }, @@ -451,7 +451,7 @@ pub const Interpreter = struct { }, // Raw host pointer (from libc_malloc-backed // cstring). Read bytes from real memory and copy - // into a null-terminated buffer the foreign call + // into a null-terminated buffer the extern call // can consume. .int => |addr| { const src: [*]const u8 = @ptrFromInt(@as(usize, @bitCast(addr))); @@ -461,12 +461,12 @@ pub const Interpreter = struct { tmp.append(self.alloc, buf) catch return error.TypeError; break :blk @intFromPtr(buf.ptr); }, - else => return typeErrorDetail("comptime foreign call: unsupported aggregate data-field kind (expected heap_ptr/string/int)"), + else => return typeErrorDetail("comptime extern call: unsupported aggregate data-field kind (expected heap_ptr/string/int)"), } } - return typeErrorDetail("comptime foreign call: aggregate arg must be a {ptr, len} fat-pointer pair"); + return typeErrorDetail("comptime extern call: aggregate arg must be a {ptr, len} fat-pointer pair"); }, - else => return typeErrorDetail("comptime foreign call: unsupported arg Value kind"), + else => return typeErrorDetail("comptime extern call: unsupported arg Value kind"), }; } @@ -491,7 +491,7 @@ pub const Interpreter = struct { fn callExtern(self: *Interpreter, func: *const inst_mod.Function, args: []const Value) InterpError!Value { const name = self.module.types.getString(func.name); - // A foreign call may not return (e.g. `process.exit` → `_exit`), which + // A extern call may not return (e.g. `process.exit` → `_exit`), which // would discard the interpreter's buffered `print` output (otherwise // flushed only after `#run` completes). Flush it first so comptime // diagnostics emitted just before a terminating call survive. @@ -499,13 +499,13 @@ pub const Interpreter = struct { _ = std.c.write(1, self.output.items.ptr, self.output.items.len); self.output.clearRetainingCapacity(); } - const symbol = (host_ffi.lookupSymbol(self.alloc, name) catch return bailDetail("comptime foreign call: dlsym error looking up symbol")) orelse { - if (last_bail_detail == null) last_bail_detail = "comptime foreign call: symbol not found via dlsym (target-specific binding called at compile time?)"; + const symbol = (host_ffi.lookupSymbol(self.alloc, name) catch return bailDetail("comptime extern call: dlsym error looking up symbol")) orelse { + if (last_bail_detail == null) last_bail_detail = "comptime extern call: symbol not found via dlsym (target-specific binding called at compile time?)"; return error.CannotEvalComptime; }; var packed_args: [8]usize = undefined; - if (args.len > packed_args.len) return bailDetail("comptime foreign call: more than 8 args (host_ffi trampolines max out at 8)"); + if (args.len > packed_args.len) return bailDetail("comptime extern call: more than 8 args (host_ffi trampolines max out at 8)"); var tmp = std.ArrayList([]u8).empty; defer { @@ -517,7 +517,7 @@ pub const Interpreter = struct { } const argv = packed_args[0..args.len]; - // Variadic foreign functions (declared `args: ..T`) must be + // Variadic extern functions (declared `args: ..T`) must be // dispatched through C-variadic trampolines so the trailing // args land in the right place per the target's variadic // ABI. The fixed-arity trampolines would put them in arg @@ -567,7 +567,7 @@ pub const Interpreter = struct { const func = self.module.getFunction(func_id); if (func.is_extern or func.blocks.items.len == 0) { // Dispatch to host libc via dlsym. Lets `#run` (and the - // post-link bundler) call ordinary foreign symbols like + // post-link bundler) call ordinary extern symbols like // `puts`, `getenv`, `posix_spawn`, etc. return self.callExtern(func, args); } @@ -863,7 +863,7 @@ pub const Interpreter = struct { const byte: u8 = @intCast(@as(u64, @bitCast(val.asInt() orelse return error.TypeError)) & 0xFF); self.heapStoreByte(hp, byte); }, - // Raw host pointer (from foreign call, e.g. libc_malloc). + // Raw host pointer (from extern call, e.g. libc_malloc). // `val_ty` carries the declared destination width so we // write exactly that many bytes — no neighbor clobber. .int => |p| { @@ -1452,7 +1452,7 @@ pub const Interpreter = struct { .offset = hp.offset + @as(u32, @intCast(offset)), } } }; }, - // Raw host pointer (from foreign call return, + // Raw host pointer (from extern call return, // e.g. libc_malloc). Byte-addressed offset // matches the heap_ptr branch above — both // are u8-granular for sx's string/slice ops. @@ -1534,7 +1534,7 @@ pub const Interpreter = struct { const result = try self.call(fid, args); return .{ .value = result }; }, - else => return bailDetail("comptime call_indirect: callee is not a func_ref Value (raw fn-pointers from foreign calls aren't dispatchable in interp)"), + else => return bailDetail("comptime call_indirect: callee is not a func_ref Value (raw fn-pointers from extern calls aren't dispatchable in interp)"), } }, diff --git a/src/ir/jni_descriptor.zig b/src/ir/jni_descriptor.zig index db622b2..328f4c0 100644 --- a/src/ir/jni_descriptor.zig +++ b/src/ir/jni_descriptor.zig @@ -16,8 +16,8 @@ // f64 → D (jdouble) // []T → [ // [*]T → [ (sx many-pointer treated as array for now) -// *Self → L; -// *Foo → L; (cross-class — step 2.9) +// *Self → L; +// *Foo → L; (cross-class — step 2.9) // // `#jni_method_descriptor("...")` (step 2.6) overrides this whole walk // when set; sema/lowering use the override verbatim. @@ -36,7 +36,7 @@ pub const DeriveError = error{ OutOfMemory, }; -/// Map from sx-side alias → foreign path of declared `#jni_class` / +/// Map from sx-side alias → runtime path of declared `#jni_class` / /// `#jni_interface` decls. Used to resolve `*Foo` into `L;` in /// the descriptor. Built during lowering's scan pass. pub const ClassRegistry = std.StringHashMap([]const u8); @@ -81,7 +81,7 @@ pub fn writeType( try writeType(allocator, buf, ctx, arr.element_type); }, .pointer_type_expr => |ptr| { - // *Self → L;, *Foo → L;, + // *Self → L;, *Foo → L;, // *void → Ljava/lang/Object; (opaque jobject — common when // users don't have a precise Java type for the value). const inner = ptr.pointee_type; diff --git a/src/ir/jni_java_emit.test.zig b/src/ir/jni_java_emit.test.zig index 7da3aeb..aabf214 100644 --- a/src/ir/jni_java_emit.test.zig +++ b/src/ir/jni_java_emit.test.zig @@ -230,7 +230,7 @@ test "default-package class (no slash in runtime_path)" { const out = try emit.emitJavaSource(a, &fcd, .{}); defer a.free(out); - // No `package ...;` line when the foreign path has no slashes. + // No `package ...;` line when the runtime path has no slashes. try std.testing.expect(std.mem.indexOf(u8, out, "package ") == null); try std.testing.expect(std.mem.indexOf(u8, out, "public class SxNoPackage") != null); } diff --git a/src/ir/jni_java_emit.zig b/src/ir/jni_java_emit.zig index e1230f0..ce64185 100644 --- a/src/ir/jni_java_emit.zig +++ b/src/ir/jni_java_emit.zig @@ -24,7 +24,7 @@ // f32/f64) // - `(self: *Self)` plus primitive params // - cross-class refs (`*Foo` where Foo is another declared -// `#foreign #jni_class`) lower to Foo's foreign path → Java +// `#jni_class(…) extern`) lower to Foo's runtime path → Java // fully-qualified type // - `*void` → `Object` (opaque jobject) @@ -39,7 +39,7 @@ pub const EmitError = error{ }; pub const Options = struct { - /// Map from sx alias → foreign path of declared `#jni_class` decls. + /// Map from sx alias → runtime path of declared `#jni_class` decls. /// Used to resolve `*Foo` cross-class refs in method signatures. classes: ?*const std.StringHashMap([]const u8) = null, /// Default superclass when the user doesn't write `#extends ...;`. @@ -79,7 +79,7 @@ pub fn injectLoadLibrary(allocator: Allocator, java_source: []const u8, lib_name return try buf.toOwnedSlice(allocator); } -/// Emit a `.java` source for the given foreign-class decl. Result is +/// Emit a `.java` source for the given runtime-class decl. Result is /// heap-allocated through `allocator`; caller owns it. pub fn emitJavaSource( allocator: Allocator, diff --git a/src/ir/lower.test.zig b/src/ir/lower.test.zig index 7d2d980..5ba3145 100644 --- a/src/ir/lower.test.zig +++ b/src/ir/lower.test.zig @@ -471,7 +471,7 @@ test "lower: objcTypeEncodingFromSignature emits @ for Obj-C class pointers" { defer module.deinit(); var lowering = Lowering.init(&module); - // Synthesize a foreign Obj-C class entry so the encoder recognises + // Synthesize a runtime Obj-C class entry so the encoder recognises // `*NSString` as an object pointer. const ns_name = module.types.internString("NSString"); const ns_struct = module.types.intern(.{ .@"struct" = .{ .name = ns_name, .fields = &.{} } }); @@ -666,7 +666,7 @@ test "lower: deriveObjcSelector — niladic / keyword / multi-keyword / override try std.testing.expectEqual(true, overridden.is_override); } -test "lower: isObjcClassPointer recognises pointer-to-foreign-Obj-C-class" { +test "lower: isObjcClassPointer recognises pointer-to-runtime-Obj-C-class" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const alloc = arena.allocator(); @@ -705,7 +705,7 @@ test "lower: isObjcClassPointer recognises pointer-to-foreign-Obj-C-class" { try lowering.program_index.runtime_class_map.put("NSCopying", &proto_fcd); try std.testing.expect(lowering.objc().isObjcClassPointer(proto_ptr)); - // *Plain where Plain is a non-foreign struct → false. + // *Plain where Plain is a non-extern struct → false. const plain_name = module.types.internString("Plain"); const plain_struct = module.types.intern(.{ .@"struct" = .{ .name = plain_name, .fields = &.{} } }); try std.testing.expect(!lowering.objc().isObjcClassPointer(module.types.ptrTo(plain_struct))); diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 7cf99ed..59ac20e 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -364,7 +364,7 @@ pub const Lowering = struct { /// Null / absent for the comptime `..$args` pack (no constraint). pack_constraint: ?std.StringHashMap([]const u8) = null, struct_const_map: std.StringHashMap(StructConstInfo), // "Struct.CONST" → value info - extern_name_map: std.StringHashMap([]const u8), // sx name → C name for #foreign renames + extern_name_map: std.StringHashMap([]const u8), // sx name → C name for #extern renames target_config: ?@import("../target.zig").TargetConfig = null, // compilation target (for inline if) comptime_constants: std.StringHashMap(ComptimeValue), // compile-time known constants (e.g. OS, ARCH) diagnostics: ?*errors.DiagnosticList = null, // error reporting with source locations @@ -836,8 +836,8 @@ pub const Lowering = struct { } return .unresolved; } - // `*Self` substitution inside foreign-class member declarations - // — both foreign and sx-defined — resolves to the class's own + // `*Self` substitution inside runtime-class member declarations + // — both runtime and sx-defined — resolves to the class's own // 0-field stub struct (i.e. the opaque Obj-C pointer type). // This matches the Obj-C idiom where `self` IS the object. // `self.field` access on sx-defined classes is rewritten by diff --git a/src/ir/lower/call.zig b/src/ir/lower/call.zig index ec79f3c..db7dc55 100644 --- a/src/ir/lower/call.zig +++ b/src/ir/lower/call.zig @@ -30,7 +30,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref { var c = c_in; // A bare reserved-type-name spelling in call position parses as a // `.type_expr` (e.g. `i2(4)`), but if a function of that name is in - // scope — a backtick-declared sx fn or a `#import c` foreign fn whose C + // scope — a backtick-declared sx fn or a `#import c` extern fn whose C // name collides with a reserved type spelling — it is a CALL to that // function. `TypeName(val)` is not a cast (casts are `cast(T, val)`), so // there is no ambiguity. Rewrite the callee to an identifier so the @@ -38,7 +38,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref { // reference that already resolves via scope/globals. // // Scoped to RAW provenance: only a backtick (`is_raw`) or `#import c` - // foreign fn declaration may legally carry a reserved-name spelling + // extern fn declaration may legally carry a reserved-name spelling // (the decl check rejects every bare reserved-name sx fn). Refusing the // rewrite for a non-raw match keeps a genuine reserved type spelling a // type — belt-and-suspenders should any future path ever reintroduce a @@ -603,7 +603,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref { return self.lowerSuperCall(fa.field, args.items, c.callee.span); } - // `Alias.method(args)` where Alias is a foreign-class + // `Alias.method(args)` where Alias is a runtime-class // identifier and `method` is a `static` member — JNI // dispatch via FindClass + GetStaticMethodID + CallStatic*, // OR (for `new`) via FindClass + GetMethodID("") + @@ -1251,7 +1251,7 @@ pub fn allocViaContext(self: *Lowering, size_ref: Ref, void_ptr_ty: TypeId) Ref } }, void_ptr_ty); } -/// Emit a call to a foreign-declared function looked up by name. +/// Emit a call to a extern-declared function looked up by name. /// Used for the compiler-internal byte-copy in the protocol-erasure /// heap path and the closure env-copy path, both of which need /// libc `memcpy` after the `#builtin` form was dropped. @@ -1285,7 +1285,7 @@ fn protocolHasMethod(proto_info: anytype, name: []const u8) bool { } pub fn resolveFuncByName(self: *Lowering, name: []const u8) ?FuncId { - // Check foreign name map first (e.g., "c_abs" → "abs") + // Check extern name map first (e.g., "c_abs" → "abs") const effective_name = self.extern_name_map.get(name) orelse name; const name_id = self.module.types.internString(effective_name); for (self.module.functions.items, 0..) |func, i| { diff --git a/src/ir/lower/closure.zig b/src/ir/lower/closure.zig index e186948..e79dea2 100644 --- a/src/ir/lower/closure.zig +++ b/src/ir/lower/closure.zig @@ -305,7 +305,7 @@ pub fn lowerLambda(self: *Lowering, lam: *const ast.Lambda) Ref { // be passed directly. For a capture-free closure whose return type matches // the slot, emit an adapter with the bare ABI. Reject the cases the bare // ABI can't represent: a capturing closure (env has nowhere to live), and - // a failable closure into a non-failable slot (foreign code can't observe + // a failable closure into a non-failable slot (extern code can't observe // the error channel — ERR E5.1 FFI-boundary rule). if (self.target_type) |tt| { if (!tt.isBuiltin() and self.module.types.get(tt) == .function) { @@ -319,7 +319,7 @@ pub fn lowerLambda(self: *Lowering, lam: *const ast.Lambda) Ref { const adapter = self.createClosureToBareFnAdapter(func_id, self.module.types.get(tt).function, ret_ty, lam.body.span); return self.builder.emit(.{ .func_ref = adapter }, tt); } else if (self.errorChannelOf(ret_ty) != null and self.errorChannelOf(slot_ret) == null) { - if (self.diagnostics) |d| d.addFmt(.err, lam.body.span, "failable closure cannot be assigned to a non-failable function-type slot; foreign code can't observe the error channel — handle the error in a wrapper closure that absorbs it", .{}); + if (self.diagnostics) |d| d.addFmt(.err, lam.body.span, "failable closure cannot be assigned to a non-failable function-type slot; extern code can't observe the error channel — handle the error in a wrapper closure that absorbs it", .{}); } else if (self.diagnostics) |d| { d.addFmt(.err, lam.body.span, "closure return type does not match the function-type slot", .{}); } diff --git a/src/ir/lower/decl.zig b/src/ir/lower/decl.zig index 444518c..5d5be9a 100644 --- a/src/ir/lower/decl.zig +++ b/src/ir/lower/decl.zig @@ -214,7 +214,7 @@ pub fn checkRequiredEntryPoints(self: *Lowering) void { diags.addFmt(.err, null, "target is Android but no `#jni_main` Activity declared. " ++ "The OS launches a Java-side Activity that delegates lifecycle " ++ "callbacks into sx — declare one like:\n\n" ++ - " Bundle :: #foreign #jni_class(\"android/os/Bundle\") {{ }}\n\n" ++ + " Bundle :: #jni_class(\"android/os/Bundle\") extern {{ }}\n\n" ++ " MyApp :: #jni_main #jni_class(\"co/example/MyApp\") {{\n" ++ " onCreate :: (self: *Self, b: *Bundle) {{ /* ... */ }}\n" ++ " }}", .{}); @@ -375,7 +375,7 @@ pub fn detectContextDecl(decls: []const *const Node) bool { } /// Returns true if a sx function declaration should receive the -/// implicit `__sx_ctx` parameter. False for foreign-libc bindings, +/// implicit `__sx_ctx` parameter. False for extern-libc bindings, /// #builtin / #compiler bodies, and C-conv functions (which keep /// their literal C ABI). Also false for OS-called entry points /// (`isExportedEntryName`): main and JNI hooks are invoked by the @@ -1101,7 +1101,7 @@ pub fn registerTopLevelGlobal(self: *Lowering, vd: *const ast.VarDecl) void { // Use self.resolveType so type aliases like `Handle :: u32;` resolve // to their target type (not a synthetic empty struct). When the // user omitted the annotation, infer from the initializer - // expression; foreign globals with no annotation are diagnosed + // expression; extern globals with no annotation are diagnosed // because their type can't be inferred without an initializer. const var_ty: TypeId = if (vd.type_annotation) |ta| self.resolveType(ta) @@ -1113,7 +1113,7 @@ pub fn registerTopLevelGlobal(self: *Lowering, vd: *const ast.VarDecl) void { break :blk .void; }; // Foreign / extern globals reference a symbol defined in libSystem etc. - // (`_NSConcreteStackBlock : *void #foreign;` or `… : *void extern;`). The C + // (`_NSConcreteStackBlock : *void extern;` or `… : *void extern;`). The C // symbol name is the optional override (`extern_name`) or the sx name itself. const sym_name = vd.extern_name orelse vd.name; const name_id = self.module.types.internString(sym_name); @@ -1397,7 +1397,7 @@ pub fn lowerRetainedSameNameAuthors(self: *Lowering) void { if (winner == fd) continue; // Only plain free functions get an out-of-line slot; generic / - // foreign / builtin / #compiler authors keep their existing + // extern / builtin / #compiler authors keep their existing // dispatch (mirrors lazyLowerFunction / declareFunction guards). if (!isPlainFreeFn(fd)) continue; @@ -1452,7 +1452,7 @@ pub const TypeHeadResolution = union(enum) { pending, /// A flat-visible author DOES declare `name` as a type, but its TypeId /// slot is not registered yet — a forward / self / mutual reference - /// resolved mid-registration (`next: *ArenaChunk`), or a foreign / + /// resolved mid-registration (`next: *ArenaChunk`), or an extern / /// lazily-registered author with no `findByName` slot. `resolveNominalLeaf` /// keeps the empty-struct stub, which `internNamedTypeDecl` ADOPTS (key- /// stable `updatePreservingKey`) when the type registers — so the forward @@ -1513,7 +1513,7 @@ pub const TypeHeadResolution = union(enum) { /// same module is one author): `≥2 distinct` → `.ambiguous`; exactly one /// that DIFFERS from the winner → select it; otherwise `.none`. /// -/// Generic / comptime / foreign / builtin authors are never rerouted — the +/// Generic / comptime / extern / builtin authors are never rerouted — the /// existing dispatch owns those shapes; `isPlainFreeFn` filters them out /// BEFORE the count gate (so a same-name collision of non-plain authors is /// NOT ambiguous), and the selector returns `.none`. No eager @@ -1540,7 +1540,7 @@ pub fn selectPlainCallableAuthor(self: *Lowering, name: []const u8, caller_file: // Caller does not author `name` as a fn → its flat-reachable authors. // Filter to plain free functions BEFORE counting: a same-name collision - // of non-plain authors (e.g. two flat-imported modules each `#foreign`ing + // of non-plain authors (e.g. two flat-imported modules each `extern`ing // the same symbol) is NOT counted as ambiguous — it falls through to // `.none` and the existing first-wins path. var the_one: ?*const ast.FnDecl = null; @@ -1597,7 +1597,7 @@ pub fn selectNominalLeaf(self: *Lowering, name: []const u8, from: []const u8, ra } // Bare nominal name. A bare TYPE name is visible iff a flat-import- // reachable module authors it AS A TYPE — and a TYPE author is EITHER a - // named type (struct/enum/union/error-set/protocol/foreign class) OR a + // named type (struct/enum/union/error-set/protocol/runtime class) OR a // type ALIAS (`Name :: `, a `const_decl` whose value resolved to a // type, recorded in E0's `type_aliases_by_source`). Both kinds are gated // identically: `moduleTypeAuthor` is the SINGLE source of truth, so a @@ -1741,7 +1741,7 @@ pub fn selectNominalLeaf(self: *Lowering, name: []const u8, from: []const u8, ra } /// TRUE iff `raw` declares a NAMED TYPE — struct / enum / union / error-set / -/// protocol / foreign class. A `fn_decl`, a value-or-alias `const_decl`, and a +/// protocol / runtime class. A `fn_decl`, a value-or-alias `const_decl`, and a /// `namespace_decl` are NOT named types. A type ALIAS is a `const_decl`; /// it is recognised via `type_aliases_by_source` separately from named types. pub fn isNamedTypeKind(raw: resolver_mod.RawDeclRef) bool { @@ -1766,7 +1766,7 @@ pub fn isNamedTypeKind(raw: resolver_mod.RawDeclRef) bool { /// through `internNamedTypeDecl` (`registerEnumDecl` / `registerUnionDecl`), /// keyed by the raw-facts decl pointer, with the `findByName` fallback for a /// single author registered before its slot lands. error-set / protocol / -/// foreign-class keep the legacy `findByName` resolution (their same-name +/// runtime-class keep the legacy `findByName` resolution (their same-name /// shadows are later E6 sub-steps — E6b/E6c/E6d). pub fn namedRefTid(self: *Lowering, ref: resolver_mod.RawDeclRef, name: []const u8) ?TypeId { const table = &self.module.types; @@ -1831,7 +1831,7 @@ pub fn localTypeInAnySource(self: *Lowering, name: []const u8) bool { /// Resolve the bare TYPE leaf to a `TypeId` for `resolveTypeWithBindings`. /// Routes through the source-aware `selectNominalLeaf`. `.pending` (forward /// alias) and `.forward` (a real author not interned yet — self / forward / -/// foreign reference) keep the empty-struct stub, which the type ADOPTS on +/// extern reference) keep the empty-struct stub, which the type ADOPTS on /// registration (`internNamedTypeDecl`). `.undeclared` (NO author anywhere) /// is genuinely-undeclared: in a NON-main module — which the /// `UnknownTypeChecker` trusts and never walks — the leaf is the only guard, @@ -2298,14 +2298,14 @@ pub fn lazyLowerFunction(self: *Lowering, name: []const u8) void { if (self.lookupObjcDefinedClassForMethod(name)) |fcd| { self.current_runtime_class = fcd; } - // No AST? (builtins, foreign functions, or imported functions not in this file) + // No AST? (builtins, extern functions, or imported functions not in this file) const fd = self.program_index.fn_ast_map.get(name) orelse return; // Foreign declarations stay as extern stubs but need to be REGISTERED // in the current module so callers get a real FuncId. Without this, // a comptime-lowered function (e.g. `concat` from std.sx pulled into // a fresh ct_module via `evalComptimeString`) emits `.call` against a // FuncId that doesn't exist locally; the interp can't find the - // foreign target and silently no-ops instead of dispatching to libc. + // extern target and silently no-ops instead of dispatching to libc. if (fd.extern_export == .extern_) { if (self.resolveFuncByName(name) == null) { self.declareFunction(fd, name); @@ -2511,10 +2511,10 @@ pub fn lowerFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8, i }) catch unreachable; } - // Check if the function body is a builtin or foreign declaration (no body + // Check if the function body is a builtin or extern declaration (no body // needed). `extern` imports are declare-only too (empty placeholder body). if (fd.body.data == .builtin_expr or fd.body.data == .compiler_expr or fd.extern_export == .extern_) { - // Already declared by scanDecls/declareFunction (which handles #foreign renames) + // Already declared by scanDecls/declareFunction (which handles #extern renames) return; } diff --git a/src/ir/lower/expr.zig b/src/ir/lower/expr.zig index 81ecde4..76159ff 100644 --- a/src/ir/lower/expr.zig +++ b/src/ir/lower/expr.zig @@ -567,7 +567,7 @@ pub fn lowerFieldAccess(self: *Lowering, fa: *const ast.FieldAccess, span: ast.S } // M2.2 — `obj.field` where `field` is declared with `#property` - // on a foreign Obj-C class lowers as `[obj field]` (the synthesized + // on a runtime Obj-C class lowers as `[obj field]` (the synthesized // getter). Receiver stays opaque — no auto-deref. if (self.lookupObjcPropertyOnPointer(fa.object, fa.field)) |prop| { return self.lowerObjcPropertyGetter(fa.object, prop, fa.field, span); diff --git a/src/ir/lower/ffi.zig b/src/ir/lower/ffi.zig index 9bc22ab..29191fb 100644 --- a/src/ir/lower/ffi.zig +++ b/src/ir/lower/ffi.zig @@ -228,7 +228,7 @@ pub fn lowerJniCall(self: *Lowering, fic: *const ast.FfiIntrinsicCall) Ref { } }, ret_ty); } -/// Lower an `inst.method(args)` call where `inst`'s type is a foreign-class +/// Lower an `inst.method(args)` call where `inst`'s type is a runtime-class /// alias declared by `#jni_class("...") { ... }` (or its parallel forms). /// JNI runtimes lower directly to `jni_msg_send` with a descriptor derived /// from the method's sx signature; Obj-C / Swift runtimes are deferred to @@ -252,7 +252,7 @@ pub fn lowerRuntimeMethodCall( // child receiver, not the parent. const found = self.findRuntimeMethodInChain(fcd, method_name) orelse { if (self.diagnostics) |d| { - d.addFmt(.err, span, "no method '{s}' on foreign class '{s}' (or any `#extends` ancestor)", .{ method_name, fcd.name }); + d.addFmt(.err, span, "no method '{s}' on runtime class '{s}' (or any `#extends` ancestor)", .{ method_name, fcd.name }); } return Ref.none; }; @@ -263,7 +263,7 @@ pub fn lowerRuntimeMethodCall( // receiver derives a selector from the sx method name (default // mangling: split on `_`, each piece becomes a keyword with a // trailing `:`; niladic stays verbatim) and lowers to - // `objc_msg_send`. Both foreign and sx-defined classes flow + // `objc_msg_send`. Both runtime and sx-defined classes flow // through the same path — sx-defined classes have their IMPs // registered at module-init (M1.2 A.4b.iii) so `objc_msgSend` // finds them. The Swift runtimes still bail — Phase 4. @@ -292,7 +292,7 @@ pub fn lowerRuntimeMethodCall( const env_ref = self.jni_env_stack.items[self.jni_env_stack.items.len - 1]; // Build a ClassRegistry snapshot so descriptor derivation can - // resolve `*Foo` cross-class refs to their foreign paths. + // resolve `*Foo` cross-class refs to their runtime paths. var registry = jni_descriptor.ClassRegistry.init(self.alloc); defer registry.deinit(); var it = self.program_index.runtime_class_map.iterator(); @@ -353,8 +353,8 @@ pub fn lowerRuntimeMethodCall( // `self.objc()`. Emission-heavy IMP builders live in lower/objc_class.zig; // the `lowerObjc*Call` lowering paths are below. -/// Resolve a foreign-class member type, substituting `Self` (and `*Self`) -/// with the foreign class's own struct type. Without this substitution +/// Resolve a runtime-class member type, substituting `Self` (and `*Self`) +/// with the runtime class's own struct type. Without this substitution /// chained calls like `Cls.alloc().init()` see the inner result as a /// fictitious `Self` struct and the next dispatch lookup fails. pub fn resolveRuntimeClassMemberType( @@ -559,7 +559,7 @@ pub fn lowerObjcStaticCall( } }, ret_ty); } -/// Lower `Alias.new(args)` where `Alias` is a foreign-class identifier +/// Lower `Alias.new(args)` where `Alias` is a runtime-class identifier /// with `static new :: (...) -> *Self;` — JNI constructor dispatch: /// `FindClass + GetMethodID("", "(args)V") + NewObject(env, /// clazz, mid, args...)`. Returns the new jobject. @@ -587,7 +587,7 @@ pub fn lowerRuntimeStaticCall( return Ref.none; } if (!std.mem.eql(u8, method.name, "new")) { - if (self.diagnostics) |d| d.addFmt(.err, span, "static foreign-class call '{s}.{s}' not yet supported via `Alias.method()` syntax \u{2014} only `new` is wired today; use `#jni_static_call` directly for other static methods", .{ fcd.name, method.name }); + if (self.diagnostics) |d| d.addFmt(.err, span, "static runtime-class call '{s}.{s}' not yet supported via `Alias.method()` syntax \u{2014} only `new` is wired today; use `#jni_static_call` directly for other static methods", .{ fcd.name, method.name }); return Ref.none; } @@ -628,7 +628,7 @@ pub fn lowerRuntimeStaticCall( }; // sx-side return type is `*Self` — resolve to a pointer to the - // foreign-class struct type so method dispatch on the new + // runtime-class struct type so method dispatch on the new // jobject works (`view := SurfaceView.new(ctx); view.getHolder()`). // At LLVM level still ptr; the sx type table is what method // resolution consults. @@ -671,7 +671,7 @@ pub fn lowerRuntimeStaticCall( /// method's name (the common case — `super.onCreate(b)` from inside /// `onCreate :: (self, b)` override), the enclosing method's /// signature is reused. Other method names require the parent class -/// to be declared via `#foreign #jni_class` so the signature can be +/// to be declared via `#jni_class(…) extern` so the signature can be /// looked up. pub fn lowerSuperCall( self: *Lowering, @@ -701,7 +701,7 @@ pub fn lowerSuperCall( // Resolve method signature. Same-name fast path reuses the // enclosing method's descriptor; cross-method super calls require - // the parent class to be declared via `#foreign #jni_class`. + // the parent class to be declared via `#jni_class(…) extern`. var descriptor: []const u8 = ""; var resolved_method: ?ast.RuntimeMethodDecl = null; if (self.current_runtime_method) |em| { @@ -725,7 +725,7 @@ pub fn lowerSuperCall( } } const method = resolved_method orelse { - if (self.diagnostics) |d| d.addFmt(.err, span, "no method '{s}' found for `super.{s}(...)` — declare the parent class via `#foreign #jni_class` to make cross-method super calls available", .{ method_name, method_name }); + if (self.diagnostics) |d| d.addFmt(.err, span, "no method '{s}' found for `super.{s}(...)` — declare the parent class via `#jni_class(…) extern` to make cross-method super calls available", .{ method_name, method_name }); return Ref.none; }; @@ -780,13 +780,13 @@ pub fn lowerSuperCall( // ── Foreign-class registration ────────────────────────────────── -/// Register a foreign-class declaration. The alias goes into +/// Register a runtime-class declaration. The alias goes into /// `runtime_class_map` for method-dispatch lookup. The underlying /// type (e.g. `*Activity`) is resolved via the existing struct /// fallback in `type_bridge.resolveTypeName` (which interns unknown /// named types as 0-field structs). /// -/// sx-defined Obj-C classes (no `#foreign`, runtime == .objc_class) +/// sx-defined Obj-C classes (no `extern`, runtime == .objc_class) /// also land in `module.objc_defined_class_cache` in declaration /// order AND have their bodied methods registered into `fn_ast_map` /// under qualified names `.`. Lazy lowering @@ -821,7 +821,7 @@ pub fn registerRuntimeClassDecl(self: *Lowering, fcd: *const ast.RuntimeClassDec /// Resolve the `#extends ParentAlias` declaration on a sx-defined /// `#objc_class` to the actual Obj-C runtime class name. Falls /// back to "NSObject" when no `#extends` is declared. -/// Aliases that resolve to foreign Obj-C classes use the +/// Aliases that resolve to runtime Obj-C classes use the /// runtime_path; aliases for OTHER sx-defined classes use the /// alias name directly (which equals the Obj-C class name for /// sx-defined classes). @@ -1007,7 +1007,7 @@ pub fn getJniEnvTlFids(self: *Lowering) struct { get: FuncId, set: FuncId } { return .{ .get = self.jni_env_tl_get_fid.?, .set = self.jni_env_tl_set_fid.? }; } -/// When a namespaced import (`Ns :: #import "..."`) contains foreign-class +/// When a namespaced import (`Ns :: #import "..."`) contains runtime-class /// declarations, ALSO register them under their qualified name `Ns.Class` /// so receiver types like `*Ns.Class` can find the fcd. The recursive /// scan/lower already handles bare-name registration; this only adds the @@ -1169,7 +1169,7 @@ pub fn synthesizeJniMainStub(self: *Lowering, fcd: *const ast.RuntimeClassDecl, } /// JNI param/return type resolution: user-declared types pass through -/// `resolveType` so the method body can dispatch on richer foreign-class +/// `resolveType` so the method body can dispatch on richer runtime-class /// types (`holder.getSurface()` etc.). At LLVM level both `*SurfaceHolder` /// and `*void` lower to the same `ptr`, so the C ABI shape Java sees is /// unchanged — only sx-side method resolution benefits. diff --git a/src/ir/lower/generic.zig b/src/ir/lower/generic.zig index 74db0e9..46d2ee0 100644 --- a/src/ir/lower/generic.zig +++ b/src/ir/lower/generic.zig @@ -808,14 +808,14 @@ pub fn hasComptimeParams(fd: *const ast.FnDecl) bool { } /// A plain free function: no type params (not generic) and an ordinary sx -/// body (not `#foreign` / `#builtin` / `#compiler` / `extern`). Only these get +/// body (not `extern` / `#builtin` / `#compiler` / `extern`). Only these get /// an out-of-line identity-addressable slot — the bare-call disambiguation /// and the shadow-author lowering pass leave every other shape /// to the existing name-keyed dispatch. pub fn isPlainFreeFn(fd: *const ast.FnDecl) bool { if (fd.type_params.len > 0) return false; // An `extern` import is an external C symbol with no sx-lowerable body — - // name-keyed first-wins dispatch like a `#foreign` body, never a plain free + // name-keyed first-wins dispatch like a `extern` body, never a plain free // fn. `export` DEFINES a real body, so it stays plain-free. if (fd.extern_export == .extern_) return false; return switch (fd.body.data) { @@ -1032,7 +1032,7 @@ pub fn headNameOfCallee(callee: *const Node) ?HeadName { /// (`.proceed`) when import facts are unwired, the source context is absent, /// the default-Context emitter is running (built-in infrastructure resolves /// independent of the user's import style, F1), the querying source is the OWN -/// author, a single flat author is not registered yet (a forward / foreign / +/// author, a single flat author is not registered yet (a forward / extern / /// generic template — the caller instantiates it), or `name` is a block-local /// of this source / no type author at all. Library-internal heads stay visible /// because every instantiation kind is source-pinned to the template's defining diff --git a/src/ir/lower/nominal.zig b/src/ir/lower/nominal.zig index 77f4f51..d527c84 100644 --- a/src/ir/lower/nominal.zig +++ b/src/ir/lower/nominal.zig @@ -257,7 +257,7 @@ pub fn shadowNominalId(self: *Lowering, name_id: types.StringId) u32 { } /// TRUE iff `name` is authored AS A NAMED TYPE (struct / enum / union / -/// error-set / protocol / foreign class) by ≥2 DISTINCT modules in the import +/// error-set / protocol / runtime class) by ≥2 DISTINCT modules in the import /// raw facts — the authoritative same-name-shadow signal (the only case where /// distinct `nominal_id`s are needed). Module distinctness is by LEXICALLY /// NORMALIZED path: one logical file reached through several spellings diff --git a/src/ir/lower/objc_class.zig b/src/ir/lower/objc_class.zig index 2aaaf6b..b8aafa9 100644 --- a/src/ir/lower/objc_class.zig +++ b/src/ir/lower/objc_class.zig @@ -53,7 +53,7 @@ pub fn lowerObjcDefinedClassMethods(self: *Lowering) void { self.emitObjcDefinedClassImps(); } -/// If `obj_expr` is typed as a pointer to a foreign Obj-C class +/// If `obj_expr` is typed as a pointer to a runtime Obj-C class /// and that class (or any of its `#extends` ancestors) declares a /// `#property` field with the given name, return the /// `RuntimeFieldDecl`. M2.2 + M2.3. @@ -257,7 +257,7 @@ pub fn lowerObjcPropertySetter(self: *Lowering, obj_expr: *const ast.Node, field /// Get a FuncId for an external C-callconv function. If a function /// with this exported name already exists in the module (e.g. -/// declared by stdlib `#foreign` decl), return it; otherwise +/// declared by stdlib `extern` decl), return it; otherwise /// declare it fresh with the given signature. /// /// One helper instead of a `getFid` per runtime function — @@ -729,7 +729,7 @@ pub fn emitObjcDefinedClassImp(self: *Lowering, fcd: *const ast.RuntimeClassDecl // Pass the Obj-C receiver pointer through to the sx body as // `self`. The body's `self: *Self` type resolves to the - // foreign-class stub (the opaque Obj-C type), matching Apple's + // runtime-class stub (the opaque Obj-C type), matching Apple's // Obj-C semantics where `self` IS the object. `self.field` // access on a sx-defined class is rewritten by lowerFieldAccess // to go through `object_getIvar(self, __sx_state_ivar)` and diff --git a/src/ir/module.zig b/src/ir/module.zig index d2a6e67..a21580d 100644 --- a/src/ir/module.zig +++ b/src/ir/module.zig @@ -43,7 +43,7 @@ pub const Module = struct { /// the class object through this cache once per module. objc_class_cache: std.ArrayList(ObjcClassEntry), /// sx-defined Obj-C classes — every `Cls :: #objc_class("Cls") { ... }` - /// declaration WITHOUT `#foreign`. Insertion-ordered so the + /// declaration WITHOUT `extern`. Insertion-ordered so the /// class-registration constructors (M1.2 A.4) emit in source order /// — parent classes register before children, which matters because /// `objc_allocateClassPair(super, ...)` resolves `super` by lookup. diff --git a/src/ir/resolver.zig b/src/ir/resolver.zig index ae82231..0e10e31 100644 --- a/src/ir/resolver.zig +++ b/src/ir/resolver.zig @@ -63,7 +63,7 @@ pub const VisibilityMode = enum { /// own scope ∪ `flat_import_graph`. The PERMANENT core for bare-name lookup /// under flat imports (Agra constraint) — never a transitional path. user_bare_flat, - /// `user_bare_flat` plus the foreign-C gate (today's `isCImportVisible`): + /// `user_bare_flat` plus the extern-C gate (today's `isCImportVisible`): /// only C-import `fn_decl`s without a `library_ref` are policed; everything /// else is unconditionally visible. c_import_bare, @@ -172,13 +172,13 @@ pub fn fnDeclOf(raw: RawDeclRef) ?*const ast.FnDecl { }; } -/// A PLAIN free function — no type params, an ordinary (non-`#foreign`/ +/// A PLAIN free function — no type params, an ordinary (non-`extern`/ /// `#builtin`/`#compiler`/`extern`) body — the only callable kind the bare-call /// verdict counts. pub fn isPlainFreeFnDecl(fd: *const ast.FnDecl) bool { if (fd.type_params.len > 0) return false; // An `extern` import is an external C symbol with no sx-lowerable body — - // dispatched name-keyed first-wins, exactly like a `#foreign` body, so it + // dispatched name-keyed first-wins, exactly like a `extern` body, so it // is NOT a plain free fn (excluded from the bare-call ambiguity verdict and // the out-of-line-slot / shadow-author pass). `export` DEFINES a real sx // body, so it stays plain-free. @@ -227,8 +227,8 @@ pub fn classifyHeadKind(raw: RawDeclRef, gs: *bool, tf: *bool, pr: *bool) void { } } -/// True when the bare-type verdict selected a foreign-class author -/// unambiguously. Used by lowering to route to the foreign-class path. +/// True when the bare-type verdict selected a runtime-class author +/// unambiguously. Used by lowering to route to the runtime-class path. pub fn runtimeClassWinsType(set: AuthorSet, verdict: Verdict) bool { return switch (verdict) { .own_wins => if (set.own) |a| std.meta.activeTag(a.raw) == .runtime_class_decl else false, diff --git a/src/ir/semantic_diagnostics.zig b/src/ir/semantic_diagnostics.zig index de425a8..de5accf 100644 --- a/src/ir/semantic_diagnostics.zig +++ b/src/ir/semantic_diagnostics.zig @@ -33,7 +33,7 @@ const TypeResolver = type_resolver.TypeResolver; /// imported / library modules are trusted, matching `checkErrorFlow`. /// /// Queries the canonical facts rather than maintaining a parallel authoritative -/// list: declared top-level names come from `ProgramIndex` (foreign classes, +/// list: declared top-level names come from `ProgramIndex` (runtime classes, /// generic templates, protocols, aliases) plus the AST decl/scope walk (for /// LOCAL type decls, which `ProgramIndex` doesn't track); primitives come from /// `TypeResolver.resolvePrimitive`; registered concrete types from the @@ -138,7 +138,7 @@ pub const UnknownTypeChecker = struct { // A function NAME is a binding site too: a bare reserved-name // `i2 :: (…) {…}` (free fn or struct/impl method) is rejected, // exactly like `i2 := …`. Backtick (`` `i2 :: … ``) and - // `#import c` foreign fns set `is_raw` and are exempt (0089). + // `#import c` extern fns set `is_raw` and are exempt (0089). self.checkBindingName(fd.name, fd.name_span, fd.is_raw); self.checkParamNames(fd.params); self.checkBindingNames(fd.body); @@ -194,7 +194,7 @@ pub const UnknownTypeChecker = struct { if (os.binding) |b| self.checkBindingName(b, os.binding_span, os.binding_is_raw); self.checkBindingNames(os.body); }, - // impl / protocol-default / foreign-class method bodies: each + // impl / protocol-default / runtime-class method bodies: each // method introduces its own params + locals. A `#jni_main` / // `#objc_class` bodied method is lowered (M1.2), so its reserved // param/local names mis-lower the same as any other. @@ -365,7 +365,7 @@ pub const UnknownTypeChecker = struct { /// (a lambda default), so recurse into it. fn checkParamNames(self: UnknownTypeChecker, params: []const ast.Param) void { for (params) |p| { - // A backtick raw param (`` (`i2: T) ``) or a `#import c` foreign + // A backtick raw param (`` (`i2: T) ``) or a `#import c` extern // param is exempt from the reserved-type-name rule — // the exemption is honored inside `checkBindingName` via `p.is_raw`. self.checkBindingName(p.name, p.name_span, p.is_raw); @@ -375,7 +375,7 @@ pub const UnknownTypeChecker = struct { /// Collect every top-level name that can legitimately appear in a type /// position: const-decl names (covers `T :: struct/enum/union/error/alias` - /// and value consts), plus the scan-populated foreign-class / generic- + /// and value consts), plus the scan-populated runtime-class / generic- /// template / protocol / alias maps from `ProgramIndex`. Built across ALL /// files so a main-file reference to an imported type isn't flagged. fn collectDeclaredTypeNames(self: UnknownTypeChecker, decls: []const *const Node, out: *std.StringHashMap(void)) void { @@ -860,7 +860,7 @@ pub const UnknownTypeChecker = struct { /// correct without any lowering special-case. /// `is_raw` is a REQUIRED argument, not a call-site guard: the exemption /// lives INSIDE the check so no caller can validate a name without also - /// honoring the backtick / `#import c` foreign exemption. This is what keeps + /// honoring the backtick / `#import c` extern exemption. This is what keeps /// the check and the exemption from desyncing — the recurring failure of the /// earlier attempts, where each site threaded an `if (!is_raw)` guard /// separately and one was forgotten. @@ -872,12 +872,12 @@ pub const UnknownTypeChecker = struct { /// Reserved-name check for a `::` declaration whose own name binds an /// identifier but carries no dedicated `name_span` field — struct / enum / - /// union / error-set / protocol / foreign-class type decls, ufcs aliases, + /// union / error-set / protocol / runtime-class type decls, ufcs aliases, /// and namespaced imports. Each such node begins at its name /// token (`createNode(name_start, …)`), so the name's length isolates the /// caret onto the name — a single source for the span, no separate stored /// field to drift from `node.span`. `is_raw` is REQUIRED, exactly as in - /// `checkBindingName`: a backtick raw / `#import c` foreign name is exempt + /// `checkBindingName`: a backtick raw / `#import c` extern name is exempt /// by construction. fn checkDeclName(self: UnknownTypeChecker, node: *const Node, name: []const u8, is_raw: bool) void { const span = ast.Span{ .start = node.span.start, .end = node.span.start + @as(u32, @intCast(name.len)) }; diff --git a/src/lsp/server.zig b/src/lsp/server.zig index 8dd75fb..626065d 100644 --- a/src/lsp/server.zig +++ b/src/lsp/server.zig @@ -1322,7 +1322,7 @@ pub const Server = struct { } return; } - // Skip functions, types, structs, enums, unions, comptime, foreign, library + // Skip functions, types, structs, enums, unions, comptime, extern, library switch (cd.value.data) { .fn_decl, .type_expr, .struct_decl, .enum_decl, .union_decl, .comptime_expr, .library_decl, diff --git a/src/main.zig b/src/main.zig index d2858e9..0e89752 100644 --- a/src/main.zig +++ b/src/main.zig @@ -270,7 +270,7 @@ pub fn main(init: std.process.Init) !void { defer c_handle.unload(io); timer.record("c-import"); - // dlopen #library dependencies so JIT can resolve foreign symbols. + // dlopen #library dependencies so JIT can resolve extern symbols. // Program-owned dylibs (the #import c unit first, then #library // deps in declaration order) also become PRIORITY search targets // for the JIT, consulted before the process-wide fallback. diff --git a/src/parser.zig b/src/parser.zig index 9ceea8e..4979952 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -250,19 +250,20 @@ pub const Parser = struct { return self.parseProtocolDecl(name, start_pos, name_is_raw); } - // Foreign-type binding with optional prefix modifiers: - // [#foreign | #jni_main]* (#jni_class / #jni_interface / #objc_class / + // Runtime-class binding with an optional `#jni_main` prefix modifier: + // [#jni_main]* (#jni_class / #jni_interface / #objc_class / // #objc_protocol / #swift_class / #swift_struct / #swift_protocol) ("path") { body } // // Define-by-default: bare `#jni_class("...")` declares a new class (sx-defined). - // `#foreign` flips that to "reference an existing class on the foreign side." - // `#jni_main` flags the class as the launchable entry (Android Activity). + // Postfix `extern` flips that to "reference an existing class on the runtime + // side". `#jni_main` flags the class as the launchable entry (Android Activity). const prefix_loc = self.current.loc; if (self.tryParseRuntimeClassPrefix()) |prefix| { - // Phase 8 cutover: the prefix `#foreign` on a runtime-class directive is - // removed — reference an existing class via the postfix `extern` modifier - // (`X :: #objc_class("…") extern { … }`) instead. `prefix_loc` pins the - // diagnostic to the `#foreign` token (already consumed by the lookahead). + // Phase 8 cutover: the removed prefix linkage directive on a + // runtime-class directive — reference an existing class via the + // postfix `extern` modifier (`X :: #objc_class("…") extern { … }`) + // instead. `prefix_loc` pins the diagnostic to the removed-directive + // token (already consumed by the lookahead). if (prefix.is_extern) { return self.failAt(prefix_loc, "`#foreign` has been removed; use the postfix `extern` (import) / `export` (define) linkage keyword instead"); } @@ -320,9 +321,9 @@ pub const Parser = struct { return try self.createNode(start_pos, .{ .const_decl = .{ .name = name, .type_annotation = value, .value = bi, .name_span = name_span, .is_raw = name_is_raw } }); } - // Phase 8 cutover: the prefix `#foreign` linkage directive has been - // removed — reject it with a migration message (was: `name :: type - // #foreign [lib] ["c_name"];`, now `name :: type extern [lib] ["c_name"];`). + // Phase 8 cutover: the removed prefix linkage directive on a + // const-with-type decl — reject it with a migration message (the + // postfix form is `name :: type extern [lib] ["c_name"];`). if (self.current.tag == .hash_foreign) { return self.fail("`#foreign` has been removed; use the postfix `extern` (import) / `export` (define) linkage keyword instead"); } @@ -411,16 +412,16 @@ pub const Parser = struct { return try self.createNode(start_pos, .{ .var_decl = .{ .name = name, .name_span = name_span, .type_annotation = type_node, .value = null, .is_raw = name_is_raw } }); } - // Phase 8 cutover: prefix `#foreign` on a data global is removed — - // reject it (was `name : type #foreign [lib] ["c_name"];`, now - // `name : type extern [lib] ["c_name"];`, handled by the `kw_extern` arm). + // Phase 8 cutover: the removed prefix linkage directive on a data + // global — reject it (the postfix form `name : type extern [lib] + // ["c_name"];` is handled by the `kw_extern` arm below). if (self.current.tag == .hash_foreign) { return self.fail("`#foreign` has been removed; use the postfix `extern` (import) / `export` (define) linkage keyword instead"); } if (self.current.tag == .kw_extern) { // name : type extern [LIB] ["csym"]; (extern data global — the - // extern-named counterpart of `#foreign`; resolved at link time) + // extern-named counterpart of `extern`; resolved at link time) self.advance(); var ext_lib: ?[]const u8 = null; if (self.current.tag == .identifier) { @@ -446,7 +447,7 @@ pub const Parser = struct { } }); } - return self.fail("expected ':', '=', ';', '#foreign', or 'extern' after type annotation"); + return self.fail("expected ':', '=', ';', or 'extern' after type annotation"); } fn parseTypeExpr(self: *Parser) anyerror!*Node { @@ -1299,9 +1300,9 @@ pub const Parser = struct { is_main: bool, }; - /// Recognise an optional sequence of `#foreign` / `#jni_main` modifiers + /// Recognise an optional sequence of `extern` / `#jni_main` modifiers /// followed by a type-introducer directive (`#jni_class`, `#objc_class`, - /// ...). Returns null if the current position isn't a foreign-class + /// ...). Returns null if the current position isn't a runtime-class /// directive (possibly after modifiers). Consumes the modifier tokens /// only when a runtime directive follows; otherwise leaves the parser /// state untouched. @@ -1368,31 +1369,22 @@ pub const Parser = struct { try self.expect(.l_paren); if (self.current.tag != .string_literal) { - return self.fail("expected string literal foreign-type path after directive"); + return self.fail("expected string literal runtime-class type path after directive"); } const raw = self.tokenSlice(self.current); const runtime_path = raw[1 .. raw.len - 1]; self.advance(); try self.expect(.r_paren); - // Phase 3 (FFI-linkage): optional postfix `extern` / `export` after the - // `#objc_class("X")` directive — the new spelling that replaces the prefix - // `#foreign` modifier (mirrors `struct #compiler` postfix placement). - // `… extern { … }` ⇒ reference an existing runtime class (== `#foreign`). - // `… export { … }` ⇒ define + register a new sx class (== no `#foreign`). - // Maps straight onto the existing `is_extern` decision so lowering is - // unchanged. The legacy prefix `#foreign` form still works via the - // `is_extern` argument; interplay/diagnostics for combining them is Phase 4. + // The postfix `extern` / `export` modifier after the `#objc_class("X")` + // directive (mirrors `struct #compiler` postfix placement): + // `… extern { … }` ⇒ reference an existing runtime class. + // `… export { … }` ⇒ define + register a new sx class (the default). + // Maps onto `is_extern`, threaded into the runtime_class_decl node. (The + // passed `is_extern` is always false here — the removed prefix linkage + // form is rejected by the caller before this point.) var is_extern_eff = is_extern; if (self.current.tag == .kw_extern or self.current.tag == .kw_export) { - // Prefix `#foreign` and the postfix `extern`/`export` keyword are two - // spellings of the same linkage axis — combining them is contradictory - // (`#foreign`=import vs `export`=define) or redundant (`#foreign … extern`). - // Reject at the postfix keyword rather than let it silently override. - if (is_extern) { - const kw = if (self.current.tag == .kw_export) "export" else "extern"; - return self.failFmt("conflicting linkage: prefix '#foreign' cannot be combined with postfix '{s}'; use either '#foreign' or postfix 'extern'/'export', not both", .{kw}); - } is_extern_eff = self.current.tag == .kw_extern; self.advance(); } @@ -1586,7 +1578,7 @@ pub const Parser = struct { try self.expect(.r_paren); } - // Method body is optional: `;` → declaration (foreign or inherited + // Method body is optional: `;` → declaration (extern or inherited // method we just want to call); `{ ... }` → sx-side block body // for sx-defined classes; `=> expr;` → expression-body form // (M1.0), lowered as a single-statement block holding `expr`. @@ -1981,7 +1973,7 @@ pub const Parser = struct { // Optional `[LIB] ["csym"]` tail after extern/export — a library-alias // ident then a C symbol-name string, both optional (mirrors - // `#foreign LIB "csym"`). Stored on extern_lib/extern_name; the rename + // `extern LIB "csym"`). Stored on extern_lib/extern_name; the rename // is consumed in `declareFunction`, the lib reference in Part B. var extern_lib: ?[]const u8 = null; var extern_name: ?[]const u8 = null; @@ -1997,7 +1989,7 @@ pub const Parser = struct { } } - // Body: block `{ ... }`, arrow `=> expr;`, #builtin, #compiler, or #foreign marker. + // Body: block `{ ... }`, arrow `=> expr;`, #builtin, or #compiler marker. // An `extern` import has NO body — just `;`. The extern_export modifier // carries the linkage; we synthesize an empty block as the (non-optional) // body placeholder, and lowering routes on the modifier rather than this @@ -2026,7 +2018,7 @@ pub const Parser = struct { self.advance(); break :blk try self.createNode(ci_start, .{ .compiler_expr = {} }); } else if (self.current.tag == .hash_foreign) { - // Phase 8 cutover: the fn-body `#foreign` marker is removed — reject it. + // Phase 8 cutover: the removed fn-body linkage marker — reject it. // The import form is now the postfix `extern` keyword handled above // (`f :: (…) -> R extern [LIB] ["csym"];`). return self.fail("`#foreign` has been removed; use the postfix `extern` (import) / `export` (define) linkage keyword instead"); @@ -3650,7 +3642,7 @@ pub const Parser = struct { // ends with `;` directly after the param list — recognise it as a // function def (not a constant) so it goes through parseFnDecl. if (self.struct_default_compiler and tag == .semicolon) return true; - // `(T1, T2) -> R` without a trailing body (`{`, `=>`, or a foreign/ + // `(T1, T2) -> R` without a trailing body (`{`, `=>`, or an extern/ // builtin marker) is a function-type literal, not a function def. if (tag == .arrow) return self.hasFnBodyAfterArrow(); // `kw_extern`/`kw_export`: a postfix linkage modifier (e.g. `f :: () extern;` @@ -4216,7 +4208,7 @@ test "parse void function with builtin body" { test "parse void function with extern import" { // A postfix `extern LIB` fn import builds an empty-block body + // extern_export = .extern_ + extern_lib. (Phase 8 removed the legacy - // prefix `#foreign` spelling that used to produce this same shape.) + // prefix `extern` spelling that used to produce this same shape.) const source = "InitWindow :: (width: i32, height: i32, title: *u8) -> void extern rl;"; var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); diff --git a/src/sema.zig b/src/sema.zig index d7c699b..15c3ee0 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -1337,7 +1337,7 @@ pub const Analyzer = struct { if (fd.is_extern and fd.is_main) { try self.diagnostics.append(self.allocator, .{ .level = .err, - .message = "'#foreign' and '#jni_main' / '#objc_main' are mutually exclusive — a foreign-referenced class can't be the app's main entry", + .message = "'extern' and '#jni_main' / '#objc_main' are mutually exclusive — a extern-referenced class can't be the app's main entry", .span = node.span, }); } @@ -1346,7 +1346,7 @@ pub const Analyzer = struct { .method => |md| if (md.body != null) { try self.diagnostics.append(self.allocator, .{ .level = .err, - .message = "methods on a '#foreign' class can't have bodies — they reference foreign-runtime implementations", + .message = "methods on a 'extern' class can't have bodies — they reference runtime implementations", .span = node.span, }); }, diff --git a/src/target.zig b/src/target.zig index 59a5ca1..fc63b60 100644 --- a/src/target.zig +++ b/src/target.zig @@ -535,7 +535,7 @@ pub fn link(allocator: std.mem.Allocator, io: std.Io, output_obj: []const u8, ex try argv.append(allocator, try std.fmt.allocPrint(allocator, "-L{s}", .{lp})); } - // Auto-detect host OS library paths when linking foreign libraries + // Auto-detect host OS library paths when linking external libraries if (libraries.len > 0 and target_config.triple == null) { for (host_lib_paths) |path| { try argv.append(allocator, try std.fmt.allocPrint(allocator, "-L{s}", .{path})); diff --git a/src/token.zig b/src/token.zig index 0e053f3..95c1ca3 100644 --- a/src/token.zig +++ b/src/token.zig @@ -137,8 +137,8 @@ pub const Tag = enum { hash_swift_class, // Foo :: #swift_class("Module.Type") { ...body... } hash_swift_struct, // Foo :: #swift_struct("Module.Type") { ...body... } hash_swift_protocol, // Foo :: #swift_protocol("Module.Proto") { ...body... } - hash_extends, // `#extends Alias;` inside a foreign-class body - hash_implements, // `#implements Alias;` inside a foreign-class body + hash_extends, // `#extends Alias;` inside a runtime-class body + hash_implements, // `#implements Alias;` inside a runtime-class body hash_jni_method_descriptor, // `#jni_method_descriptor("(Sig)Ret")` per-method JNI descriptor override hash_selector, // `#selector("explicit:string")` per-method Obj-C selector override (Phase 3.2) hash_property, // `#property[(modifier, ...)]` field directive — synthesizes getter/setter dispatch (M2.2)