feat(ffi-linkage): fn-path accepts postfix extern/export + lib/name fields (Phase 1.0a)
parseFnDecl now calls parseOptionalExternExport() after the callconv
slot and stores the modifier on FnDecl.extern_export. For 'extern' the
body is ';' (an empty-block placeholder — the modifier carries the
linkage, no *_expr node, per the naming constraint). Both fn-decl
lookahead predicates (isFunctionDef, hasFnBodyAfterArrow) now treat
kw_extern/kw_export as fn-body markers beside kw_callconv, so
'(...) -> R extern;' is recognized as a fn def rather than a fn-type
const.
Per user feedback, decision 4 ("library separate") is REVISED: extern
carries an optional LIB + "csym" axis mirroring '#foreign LIB "csym"',
so it is a true #foreign superset (Gate A->B requirement — the Part B
migration of 466 #foreign uses across 6 libs must preserve each
symbol's library). Added FnDecl.extern_lib/extern_name and
VarDecl.extern_lib (beside is_extern/extern_name).
All unconsumed by lowering: extern parses, but a fn still errors at
sema (body produces no value). Suite green (443 unit / 633 corpus).
lock commit.
This commit is contained in:
22
src/ast.zig
22
src/ast.zig
@@ -143,6 +143,15 @@ pub const FnDecl = struct {
|
||||
/// `callconv(...)` slot. `.none` for an ordinary sx-internal function.
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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
|
||||
/// functions, lowering-time objc/protocol method synthesis) leave it zero.
|
||||
@@ -355,12 +364,15 @@ pub const VarDecl = struct {
|
||||
is_foreign: bool = false,
|
||||
foreign_lib: ?[]const u8 = null,
|
||||
foreign_name: ?[]const u8 = null,
|
||||
/// `extern`-global form `g : T extern ["csym"];` — a reference to a global
|
||||
/// defined elsewhere (external linkage, resolved at link time). The new
|
||||
/// extern-named surface; distinct from the legacy `#foreign` path above.
|
||||
/// `extern_name` is the optional symbol-name override. Parsed in Phase 0.1;
|
||||
/// not consumed by the var-decl path until Phase 1.2.
|
||||
/// `extern`-global form `g : T extern [LIB] ["csym"];` — a reference to a
|
||||
/// global defined elsewhere (external linkage, resolved at link time). The
|
||||
/// new extern-named surface; distinct from the legacy `#foreign` path above.
|
||||
/// `extern_lib` is the optional source-library reference and `extern_name`
|
||||
/// the optional symbol-name override (mirroring foreign_lib/foreign_name, so
|
||||
/// `extern` fully supersedes `#foreign`). Parsed in Phase 0.1; not consumed
|
||||
/// by the var-decl path until Phase 1.2.
|
||||
is_extern: bool = false,
|
||||
extern_lib: ?[]const u8 = null,
|
||||
extern_name: ?[]const u8 = null,
|
||||
/// True when the binding name was written as a backtick raw identifier
|
||||
/// (`` `i2 := … ``). A raw name is exempt from the reserved-type-name
|
||||
|
||||
Reference in New Issue
Block a user