feat(ffi-linkage): add kw_extern/kw_export tokens (Phase 0.0)
Lex 'extern' and 'export' as keywords beside 'callconv': new token.Tag variants + keywords StaticStringMap entries + LSP semantic-token keyword classification. Adds a 'lex linkage keywords' unit test. Tokens only — parser/AST plumbing and lowering land in later phases. Corpus sweep confirmed no .sx identifier collides with the new reserved words. lock commit per the cadence rule.
This commit is contained in:
@@ -5,8 +5,13 @@ Companion to `current/PLAN-EXTERN-EXPORT.md` — one merged plan: **Part A** add
|
||||
every commit, one step at a time per the cadence rule.
|
||||
|
||||
## Last completed step
|
||||
None — plan authored, not yet started. (Merged the former EXTERN-EXPORT +
|
||||
FOREIGN-MIGRATION plans into this single plan.)
|
||||
**Phase 0.0** (lock) — added `kw_extern`/`kw_export` to `token.Tag` + the
|
||||
`keywords` `StaticStringMap` (beside `kw_callconv`, `token.zig:45,282`); classified
|
||||
both as `ST.keyword` in the LSP `classifyToken` exhaustive switch
|
||||
(`lsp/server.zig`); added `test "lex linkage keywords"` in `lexer.zig`. Suite green
|
||||
(441 unit / 633 corpus, 0 fail). `extern`/`export` are now reserved words; corpus
|
||||
sweep confirmed no `.sx` identifier used either (only comments + the unpinned
|
||||
`issues/0030-*` repro, which doesn't run in the suite).
|
||||
|
||||
## Current state
|
||||
Syntax decided + ratified: bare `extern`/`export`, postfix in the `callconv(.c)`
|
||||
@@ -15,12 +20,15 @@ slot, `extern ⇒ callconv(.c)`, library separate. Touch-points mapped — token
|
||||
`decl.zig:1123,387,2110,2382,2514`; IR/emit already capable (no codegen change).
|
||||
Export gap = 4 lowering conditions. Part B `foreign` footprint to purge: 643 lines /
|
||||
~57 identifiers in `src/` + 28 doc lines. End-state invariant: **zero `foreign`** in
|
||||
the live tree (Phase 9.4 gate). No code written.
|
||||
the live tree (Phase 9.4 gate). Tokens exist (0.0); parser/AST not yet plumbed.
|
||||
|
||||
## Next step
|
||||
**Phase 0.0** — add `kw_extern`/`kw_export` tokens + keyword-map entries (beside
|
||||
`kw_callconv`) + unit lex test. Then 0.1 (parser plumbing, unconsumed), then Phase 1
|
||||
(`extern` working). See the plan's **"Kickoff prompt"** section.
|
||||
**Phase 0.1** (lock) — `parseOptionalExternExport()` (mirror `parseOptionalCallConv`,
|
||||
`parser.zig:3669`) + `ast.ExternExportModifier` enum + `FnDecl.extern_export` +
|
||||
`VarDecl.is_extern`/`extern_name` fields; **parsed but not yet consumed**; unit AST
|
||||
test. Then Phase 1 (`extern` working: 1.0 xfail accept postfix, 1.1 green lower via
|
||||
`declareExtern`, 1.2 green rename + extern-global). See the plan's **"Kickoff
|
||||
prompt"**. Stop at end of Phase 1.
|
||||
|
||||
## Open decisions
|
||||
Part A ratified (bare / postfix / `⇒ callconv(.c)` / lib-separate). Part B (confirm
|
||||
@@ -30,6 +38,9 @@ historical carve-out — keep `issues/*.md` provenance, gate the live tree only.
|
||||
## Log
|
||||
- (init) Plan written; FFI-linkage stream opened.
|
||||
- (merge) Folded FOREIGN-MIGRATION in as Part B; deleted the split plan + checkpoint.
|
||||
- (0.0) Added `kw_extern`/`kw_export` tokens + keyword-map entries + LSP keyword
|
||||
classification + `lex linkage keywords` test. Suite green; no identifier collisions
|
||||
in the corpus. `lock` commit.
|
||||
|
||||
## Known issues
|
||||
None yet.
|
||||
|
||||
@@ -537,6 +537,15 @@ test "lex keywords" {
|
||||
}
|
||||
}
|
||||
|
||||
test "lex linkage keywords" {
|
||||
// extern / export are keywords (FFI-linkage stream), lexed beside callconv.
|
||||
var lex = Lexer.init("callconv extern export");
|
||||
const expected = [_]Tag{ .kw_callconv, .kw_extern, .kw_export };
|
||||
for (expected) |exp| {
|
||||
try std.testing.expectEqual(exp, lex.next().tag);
|
||||
}
|
||||
}
|
||||
|
||||
test "lex type-like identifiers" {
|
||||
// i32, u8, bool, string are identifiers, not keywords
|
||||
var lex = Lexer.init("i32 u8 bool string");
|
||||
|
||||
@@ -1683,6 +1683,8 @@ pub const Server = struct {
|
||||
.kw_impl,
|
||||
.kw_inline,
|
||||
.kw_callconv,
|
||||
.kw_extern,
|
||||
.kw_export,
|
||||
.hash_run,
|
||||
.hash_import,
|
||||
.hash_insert,
|
||||
|
||||
@@ -43,6 +43,8 @@ pub const Tag = enum {
|
||||
kw_Self, // Self (in protocol declarations)
|
||||
kw_inline, // inline (compile-time if/for/while)
|
||||
kw_callconv, // callconv (calling convention annotation)
|
||||
kw_extern, // extern (import: external linkage, C ABI, no body)
|
||||
kw_export, // export (define + expose: external linkage, C ABI)
|
||||
|
||||
// Symbols
|
||||
colon, // :
|
||||
@@ -280,6 +282,8 @@ pub const keywords = std.StaticStringMap(Tag).initComptime(.{
|
||||
.{ "Self", .kw_Self },
|
||||
.{ "inline", .kw_inline },
|
||||
.{ "callconv", .kw_callconv },
|
||||
.{ "extern", .kw_extern },
|
||||
.{ "export", .kw_export },
|
||||
});
|
||||
|
||||
pub fn getKeyword(bytes: []const u8) ?Tag {
|
||||
|
||||
Reference in New Issue
Block a user