refactor(ffi-linkage)!: Phase 9.0 — delete the hash_foreign token (src is foreign-free)
Per user directive (total purge): remove the hash_foreign token entirely rather than keep it for a friendly deprecation message. Deleted: the token enum (token.zig), the lexer keyword entry + directive-list mention + lex test (lexer.zig), the 4 parser rejection sites + 2 lookahead clauses + the runtime-class prefix #foreign peek arm (parser.zig), and the lsp completion arm (server.zig). '#foreign' now lexes as an invalid '#' token → a generic 'expected ;' parse error (no migration hint — the accepted UX cost of zero-foreign). Deleted examples/1176-diagnostics-foreign-removed (its purpose, the friendly rejection, no longer exists). src/ now contains ZERO 'foreign' (case-insensitive). Suite green (645 corpus / 443 unit, 0 failed). Remaining for the 9.4 gate: issues/*.md prose + example filenames.
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
// Phase 8 (FFI-linkage) cutover: the prefix `#foreign` linkage directive has
|
||||
// been removed. A declaration imports an external C symbol via the postfix
|
||||
// `extern` keyword (or defines + exposes one via `export`). The parser rejects
|
||||
// `#foreign` with a clear migration message instead of routing it onto `extern`.
|
||||
//
|
||||
// Expected: one error on the `#foreign` token; exit 1.
|
||||
|
||||
abs_c :: (n: i32) -> i32 #foreign;
|
||||
|
||||
main :: () -> i32 { 0 }
|
||||
@@ -1 +0,0 @@
|
||||
1
|
||||
@@ -1,5 +0,0 @@
|
||||
error: `#foreign` has been removed; use the postfix `extern` (import) / `export` (define) linkage keyword instead
|
||||
--> examples/1176-diagnostics-foreign-removed.sx:8:26
|
||||
|
|
||||
8 | abs_c :: (n: i32) -> i32 #foreign;
|
||||
| ^^^^^^^^
|
||||
@@ -69,7 +69,7 @@ pub const Lexer = struct {
|
||||
}
|
||||
|
||||
|
||||
// Directives: #import, #insert, #run, #builtin, #foreign, #library, #string
|
||||
// Directives: #import, #insert, #run, #builtin, #library, #string
|
||||
if (c == '#') {
|
||||
// #string needs special handling (heredoc)
|
||||
const str_kw = "#string";
|
||||
@@ -88,7 +88,6 @@ pub const Lexer = struct {
|
||||
.{ "#run", Tag.hash_run },
|
||||
.{ "#builtin", Tag.hash_builtin },
|
||||
.{ "#compiler", Tag.hash_compiler },
|
||||
.{ "#foreign", Tag.hash_foreign },
|
||||
.{ "#library", Tag.hash_library },
|
||||
.{ "#framework", Tag.hash_framework },
|
||||
.{ "#using", Tag.hash_using },
|
||||
@@ -623,15 +622,6 @@ test "lex hash_insert" {
|
||||
try std.testing.expectEqual(Tag.invalid, lex2.next().tag);
|
||||
}
|
||||
|
||||
test "lex hash_foreign" {
|
||||
var lex = Lexer.init("#foreign");
|
||||
try std.testing.expectEqual(Tag.hash_foreign, lex.next().tag);
|
||||
try std.testing.expectEqual(Tag.eof, lex.next().tag);
|
||||
|
||||
var lex2 = Lexer.init("#foreignx");
|
||||
try std.testing.expectEqual(Tag.invalid, lex2.next().tag);
|
||||
}
|
||||
|
||||
test "lex hash_library" {
|
||||
var lex = Lexer.init("#library \"raylib\"");
|
||||
try std.testing.expectEqual(Tag.hash_library, lex.next().tag);
|
||||
|
||||
@@ -1690,7 +1690,6 @@ pub const Server = struct {
|
||||
.hash_insert,
|
||||
.hash_builtin,
|
||||
.hash_compiler,
|
||||
.hash_foreign,
|
||||
.hash_library,
|
||||
.hash_framework,
|
||||
.hash_using,
|
||||
|
||||
@@ -257,16 +257,7 @@ pub const Parser = struct {
|
||||
// Define-by-default: bare `#jni_class("...")` declares a new class (sx-defined).
|
||||
// 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 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");
|
||||
}
|
||||
return self.parseRuntimeClassDecl(name, start_pos, prefix.runtime, prefix.is_extern, prefix.is_main, name_is_raw);
|
||||
}
|
||||
|
||||
@@ -321,13 +312,6 @@ 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 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");
|
||||
}
|
||||
|
||||
try self.expect(.semicolon);
|
||||
return try self.createNode(start_pos, .{ .const_decl = .{ .name = name, .type_annotation = null, .value = value, .name_span = name_span, .is_raw = name_is_raw } });
|
||||
}
|
||||
@@ -412,16 +396,9 @@ 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: 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 `extern`; resolved at link time)
|
||||
// name : type extern [LIB] ["csym"]; (extern data global, resolved
|
||||
// at link time)
|
||||
self.advance();
|
||||
var ext_lib: ?[]const u8 = null;
|
||||
if (self.current.tag == .identifier) {
|
||||
@@ -1307,17 +1284,16 @@ pub const Parser = struct {
|
||||
/// only when a runtime directive follows; otherwise leaves the parser
|
||||
/// state untouched.
|
||||
fn tryParseRuntimeClassPrefix(self: *Parser) ?RuntimeClassPrefix {
|
||||
// Peek ahead through modifier tokens to confirm a directive follows.
|
||||
// Peek ahead through the optional `#jni_main` modifier to confirm a
|
||||
// runtime-class directive follows. (`is_extern` — reference vs define —
|
||||
// is decided by the POSTFIX `extern`/`export` keyword in parseRuntimeClassDecl,
|
||||
// never a prefix; it stays false here.)
|
||||
var lookahead_idx: usize = 0;
|
||||
var is_extern = false;
|
||||
const is_extern = false;
|
||||
var is_main = false;
|
||||
while (true) {
|
||||
const tag = self.peekTag(lookahead_idx);
|
||||
switch (tag) {
|
||||
.hash_foreign => {
|
||||
is_extern = true;
|
||||
lookahead_idx += 1;
|
||||
},
|
||||
.hash_jni_main => {
|
||||
is_main = true;
|
||||
lookahead_idx += 1;
|
||||
@@ -2017,11 +1993,6 @@ pub const Parser = struct {
|
||||
const ci_start = self.current.loc.start;
|
||||
self.advance();
|
||||
break :blk try self.createNode(ci_start, .{ .compiler_expr = {} });
|
||||
} else if (self.current.tag == .hash_foreign) {
|
||||
// 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");
|
||||
} else if (self.current.tag == .fat_arrow) blk: {
|
||||
is_arrow = true;
|
||||
self.advance();
|
||||
@@ -3647,7 +3618,7 @@ pub const Parser = struct {
|
||||
if (tag == .arrow) return self.hasFnBodyAfterArrow();
|
||||
// `kw_extern`/`kw_export`: a postfix linkage modifier (e.g. `f :: () extern;`
|
||||
// with no return type) marks a fn decl just like `callconv`.
|
||||
return tag == .l_brace or tag == .hash_builtin or tag == .hash_compiler or tag == .hash_foreign or tag == .fat_arrow or tag == .kw_callconv or tag == .kw_extern or tag == .kw_export;
|
||||
return tag == .l_brace or tag == .hash_builtin or tag == .hash_compiler or tag == .fat_arrow or tag == .kw_callconv or tag == .kw_extern or tag == .kw_export;
|
||||
}
|
||||
|
||||
fn hasFnBodyAfterArrow(self: *Parser) bool {
|
||||
@@ -3673,7 +3644,7 @@ pub const Parser = struct {
|
||||
while (self.current.tag != .eof) {
|
||||
if (self.current.tag == .fat_arrow) return true;
|
||||
if (self.current.tag == .l_brace) return true;
|
||||
if (self.current.tag == .hash_builtin or self.current.tag == .hash_compiler or self.current.tag == .hash_foreign) return true;
|
||||
if (self.current.tag == .hash_builtin or self.current.tag == .hash_compiler) return true;
|
||||
if (self.current.tag == .kw_callconv) return true;
|
||||
// Postfix linkage modifier after the return type: `-> R extern;` /
|
||||
// `-> R export { … }` (and `-> R callconv(.c) extern`). Marks a fn def.
|
||||
|
||||
@@ -118,7 +118,6 @@ pub const Tag = enum {
|
||||
hash_insert, // #insert
|
||||
hash_builtin, // #builtin
|
||||
hash_compiler, // #compiler
|
||||
hash_foreign, // #foreign
|
||||
hash_library, // #library
|
||||
hash_framework, // #framework
|
||||
hash_using, // #using
|
||||
|
||||
Reference in New Issue
Block a user