Reserved type-name spellings (s1, s2, u8, …) can now be used as value identifiers two ways, resolving issue 0089: 1. Backtick raw identifier: a leading backtick (`s2) lexes to an .identifier token carrying a new Token.is_raw flag, with the backtick excluded from the text. A raw identifier is never type-classified — the parser skips Type.fromName for it — so it is always a value identifier. The flag threads to VarDecl.is_raw / Param.is_raw at binding sites, and the reserved-type-name check (UnknownTypeChecker) skips raw bindings. Because the token tag stays .identifier, the escape works in every position (local, global, param, field, fn name, struct member, later reference) with no per-site parser change. 2. #import c exemption: c_import.zig synthesizes foreign decls with Param.is_raw = true, so generated C param names that collide with reserved type names (s1, s2) import unedited. A bare reserved-name binding in sx still errors (issue 0076 preserved): the is_raw-gated skip only fires for backtick / foreign names, and a raw binding's address-of / autoref lowering stays correct because every occurrence is an .identifier, never a .type_expr. Tests: examples/0151 (backtick, every position), examples/1220 (foreign exemption, compiled+run), lexer unit tests. 1119 (bare-binding rejection) stays green. specs.md + readme.md updated.
274 lines
7.8 KiB
Zig
274 lines
7.8 KiB
Zig
pub const Tag = enum {
|
|
// Literals
|
|
int_literal,
|
|
float_literal,
|
|
string_literal,
|
|
raw_string_literal,
|
|
|
|
// Identifiers and keywords
|
|
identifier,
|
|
kw_if,
|
|
kw_else,
|
|
kw_then,
|
|
kw_true,
|
|
kw_false,
|
|
kw_enum,
|
|
kw_error, // error (error-set declaration)
|
|
kw_raise, // raise (error propagation statement)
|
|
kw_try, // try (failable-attempt prefix)
|
|
kw_catch, // catch (failable handler postfix)
|
|
kw_onfail, // onfail (error-exit cleanup statement)
|
|
kw_case,
|
|
kw_break,
|
|
kw_continue,
|
|
kw_while,
|
|
kw_for,
|
|
kw_return,
|
|
kw_defer,
|
|
kw_f32,
|
|
kw_f64,
|
|
kw_struct,
|
|
kw_union,
|
|
kw_xx,
|
|
kw_and,
|
|
kw_or,
|
|
kw_Type, // Type (metatype keyword)
|
|
kw_null, // null
|
|
kw_push, // push
|
|
kw_ufcs, // ufcs
|
|
kw_in, // in
|
|
kw_closure, // closure
|
|
kw_protocol, // protocol
|
|
kw_impl, // impl
|
|
kw_Self, // Self (in protocol declarations)
|
|
kw_inline, // inline (compile-time if/for/while)
|
|
kw_callconv, // callconv (calling convention annotation)
|
|
|
|
// Symbols
|
|
colon, // :
|
|
colon_colon, // ::
|
|
colon_equal, // :=
|
|
semicolon, // ;
|
|
comma, // ,
|
|
dot, // .
|
|
dot_dot, // ..
|
|
dollar, // $
|
|
|
|
// Operators
|
|
plus, // +
|
|
minus, // -
|
|
star, // *
|
|
slash, // /
|
|
equal, // =
|
|
equal_equal, // ==
|
|
bang, // !
|
|
bang_equal, // !=
|
|
less, // <
|
|
less_equal, // <=
|
|
greater, // >
|
|
greater_equal, // >=
|
|
plus_equal, // +=
|
|
minus_equal, // -=
|
|
star_equal, // *=
|
|
slash_equal, // /=
|
|
percent, // %
|
|
percent_equal, // %=
|
|
ampersand, // &
|
|
ampersand_equal, // &=
|
|
at, // @
|
|
pipe, // |
|
|
pipe_equal, // |=
|
|
pipe_arrow, // |>
|
|
caret, // ^
|
|
caret_equal, // ^=
|
|
question, // ?
|
|
question_question, // ??
|
|
question_dot, // ?.
|
|
tilde, // ~
|
|
less_less, // <<
|
|
less_less_equal, // <<=
|
|
greater_greater, // >>
|
|
greater_greater_equal, // >>=
|
|
|
|
// Delimiters
|
|
l_paren, // (
|
|
r_paren, // )
|
|
l_brace, // {
|
|
r_brace, // }
|
|
l_bracket, // [
|
|
r_bracket, // ]
|
|
|
|
// Arrows
|
|
arrow, // ->
|
|
fat_arrow, // =>
|
|
|
|
// Directives
|
|
hash_run, // #run
|
|
hash_import, // #import
|
|
hash_insert, // #insert
|
|
hash_builtin, // #builtin
|
|
hash_compiler, // #compiler
|
|
hash_foreign, // #foreign
|
|
hash_library, // #library
|
|
hash_framework, // #framework
|
|
hash_using, // #using
|
|
hash_include, // #include (inside #import c { ... })
|
|
hash_source, // #source (inside #import c { ... })
|
|
hash_define, // #define (inside #import c { ... })
|
|
hash_flags, // #flags (inside #import c { ... })
|
|
hash_inline, // #inline (protocol layout modifier)
|
|
hash_objc_call, // #objc_call(T)(recv, "sel:", args...)
|
|
hash_jni_call, // #jni_call(T)(env, target, "name", "(Sig)R", args...)
|
|
hash_jni_static_call, // #jni_static_call(T)(class, "name", "(Sig)R", args...)
|
|
hash_jni_class, // Foo :: #jni_class("java/path/Foo") { ...body... }
|
|
hash_jni_interface, // Foo :: #jni_interface("java/path/IFoo") { ...body... }
|
|
hash_objc_class, // Foo :: #objc_class("ObjcName") { ...body... }
|
|
hash_objc_protocol, // Foo :: #objc_protocol("ObjcProto") { ...body... }
|
|
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_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)
|
|
hash_caller_location, // `#caller_location` — as a param default, synthesizes the call site's Source_Location (ERR E4.1b)
|
|
hash_jni_env, // `#jni_env(env) { body }` block-form env-scoping intrinsic
|
|
hash_jni_main, // `#jni_main #jni_class(...) { ... }` — class is the launchable Android Activity
|
|
triple_minus, // ---
|
|
|
|
// Special
|
|
eof,
|
|
invalid,
|
|
|
|
pub fn lexeme(tag: Tag) ?[]const u8 {
|
|
return switch (tag) {
|
|
.colon => ":",
|
|
.colon_colon => "::",
|
|
.colon_equal => ":=",
|
|
.semicolon => ";",
|
|
.comma => ",",
|
|
.dot => ".",
|
|
.dot_dot => "..",
|
|
.dollar => "$",
|
|
.plus => "+",
|
|
.minus => "-",
|
|
.star => "*",
|
|
.slash => "/",
|
|
.equal => "=",
|
|
.equal_equal => "==",
|
|
.bang => "!",
|
|
.bang_equal => "!=",
|
|
.less => "<",
|
|
.less_equal => "<=",
|
|
.greater => ">",
|
|
.greater_equal => ">=",
|
|
.plus_equal => "+=",
|
|
.minus_equal => "-=",
|
|
.star_equal => "*=",
|
|
.slash_equal => "/=",
|
|
.percent => "%",
|
|
.percent_equal => "%=",
|
|
.ampersand => "&",
|
|
.ampersand_equal => "&=",
|
|
.at => "@",
|
|
.pipe => "|",
|
|
.pipe_equal => "|=",
|
|
.pipe_arrow => "|>",
|
|
.caret => "^",
|
|
.caret_equal => "^=",
|
|
.question => "?",
|
|
.question_question => "??",
|
|
.question_dot => "?.",
|
|
.tilde => "~",
|
|
.less_less => "<<",
|
|
.less_less_equal => "<<=",
|
|
.greater_greater => ">>",
|
|
.greater_greater_equal => ">>=",
|
|
.kw_null => "null",
|
|
.l_paren => "(",
|
|
.r_paren => ")",
|
|
.l_brace => "{",
|
|
.r_brace => "}",
|
|
.l_bracket => "[",
|
|
.r_bracket => "]",
|
|
.arrow => "->",
|
|
.fat_arrow => "=>",
|
|
.triple_minus => "---",
|
|
else => null,
|
|
};
|
|
}
|
|
|
|
pub fn isTypeKeyword(tag: Tag) bool {
|
|
return switch (tag) {
|
|
.kw_f32, .kw_f64, .kw_Type, .kw_Self => true,
|
|
else => false,
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const Token = struct {
|
|
tag: Tag,
|
|
loc: Loc,
|
|
/// True when an `.identifier` was introduced by a leading backtick
|
|
/// (`` `s2 ``): a RAW identifier whose text excludes the backtick and which
|
|
/// the parser must NEVER type-classify (it bypasses the reserved-type-name
|
|
/// rule). `loc` already spans only the un-backticked name, so `slice` returns
|
|
/// the bare text.
|
|
is_raw: bool = false,
|
|
|
|
pub const Loc = struct {
|
|
start: u32,
|
|
end: u32,
|
|
};
|
|
|
|
pub fn slice(self: Token, source: []const u8) []const u8 {
|
|
return source[self.loc.start..self.loc.end];
|
|
}
|
|
};
|
|
|
|
pub const keywords = std.StaticStringMap(Tag).initComptime(.{
|
|
.{ "if", .kw_if },
|
|
.{ "else", .kw_else },
|
|
.{ "then", .kw_then },
|
|
.{ "true", .kw_true },
|
|
.{ "false", .kw_false },
|
|
.{ "enum", .kw_enum },
|
|
.{ "error", .kw_error },
|
|
.{ "raise", .kw_raise },
|
|
.{ "try", .kw_try },
|
|
.{ "catch", .kw_catch },
|
|
.{ "onfail", .kw_onfail },
|
|
.{ "case", .kw_case },
|
|
.{ "break", .kw_break },
|
|
.{ "continue", .kw_continue },
|
|
.{ "while", .kw_while },
|
|
.{ "for", .kw_for },
|
|
.{ "return", .kw_return },
|
|
.{ "defer", .kw_defer },
|
|
.{ "f32", .kw_f32 },
|
|
.{ "f64", .kw_f64 },
|
|
.{ "struct", .kw_struct },
|
|
.{ "union", .kw_union },
|
|
.{ "xx", .kw_xx },
|
|
.{ "and", .kw_and },
|
|
.{ "or", .kw_or },
|
|
.{ "Type", .kw_Type },
|
|
.{ "null", .kw_null },
|
|
.{ "push", .kw_push },
|
|
.{ "ufcs", .kw_ufcs },
|
|
.{ "in", .kw_in },
|
|
.{ "closure", .kw_closure },
|
|
.{ "protocol", .kw_protocol },
|
|
.{ "impl", .kw_impl },
|
|
.{ "Self", .kw_Self },
|
|
.{ "inline", .kw_inline },
|
|
.{ "callconv", .kw_callconv },
|
|
});
|
|
|
|
pub fn getKeyword(bytes: []const u8) ?Tag {
|
|
return keywords.get(bytes);
|
|
}
|
|
|
|
const std = @import("std");
|