feat(lang): universal backtick raw identifier — valid in value, decl, AND type position [F0.6]
AGRA ruling (attempt 4): `` `name `` is THE LITERAL identifier `name`, usable in EVERY position — the backtick only means "treat this token as a plain identifier, never the reserved keyword/type", and is never part of the name's text. - Raw in TYPE position is now VALID (reverses attempt-2 "raw is not a type"): `parseTypeExpr` emits a raw `type_expr`; `TypeResolver.resolveNamed` gains a `skip_builtin` flag (threaded from `te.is_raw` via lower.zig + type_bridge) so a `` `s2 `` reference resolves to a `` `s2 ``-declared type (struct/enum/union/alias), else a normal "unknown type 's2'" error (reportIfUnknownType skips the builtin exemption when raw). Bare `s2` in type position stays the builtin int. - Every declaration-name site is is_raw-exemptible: `is_raw` added to TypeExpr + StructDecl/EnumDecl/UnionDecl/ErrorSetDecl/ProtocolDecl/ForeignClassDecl/UfcsAlias/ NamespaceDecl/ImportDecl/CImportDecl/LibraryDecl; parser threads name_is_raw to every decl parse fn; namespace imports carry it through imports.addNamespace. Typed-const path (`` `s2 : s64 : 5 ``) now threads name_span+is_raw (fixes the 1:1-caret bug). - Check<->exemption made structurally symmetric: checkBindingName/checkDeclName take is_raw as a REQUIRED argument and skip inside the check, so no call site can validate a name without honoring the exemption (the desync cause of prior rounds). - Bare reserved-name declarations of every kind still error (0076 preserved); `#import c` foreign names stay auto-raw + bare-callable. specs.md + readme.md updated to the universal model. issue 0089 RESOLVED banner rewritten. Examples: replace 1139 (raw-not-a-type) with 0154 (raw type reference); add 0155 (typed const + union tag) and 1141 (bare type-decl negatives). Gate: zig build + zig build test + run_examples (426 passed, 0 failed).
This commit is contained in:
51
specs.md
51
specs.md
@@ -38,34 +38,49 @@ sole exception: a `#builtin` constant defines the reserved type and is allowed.)
|
||||
|
||||
#### Backtick raw-identifier escape
|
||||
|
||||
A leading backtick makes the following identifier **raw**: its text excludes the
|
||||
backtick and it is never type-classified, so a reserved-type-name spelling can be
|
||||
used as an ordinary value identifier. The backtick is required at the **binding
|
||||
site** — the declaration that introduces the name — to escape the reserved-name
|
||||
rule. A later reference is resolved by position: in **value** position a bare `s2`
|
||||
resolves to the binding; in **type** position a bare `s2` is still the signed-int
|
||||
type.
|
||||
A leading backtick makes the following token a **raw identifier**: `` `name `` is
|
||||
the **literal identifier** `name` — "treat this token as a plain identifier, never
|
||||
the reserved keyword/type." The backtick is not part of the name's text (the text
|
||||
is `name`), and the escape is usable in **every position**: value, declaration,
|
||||
**and type**. It is the only way handwritten sx can spell a reserved name.
|
||||
|
||||
```sx
|
||||
`s2 := 2.5; // OK — value identifier "s2", distinct from the s2 type
|
||||
`s2 := 2.5; // OK — identifier "s2", distinct from the s2 type
|
||||
print("{}\n", `s2); // 2.5 (backtick reference)
|
||||
print("{}\n", s2); // 2.5 (bare reference, resolves to the binding)
|
||||
x : s2 = 3; // bare `s2` in TYPE position is still the s2 type
|
||||
print("{}\n", s2); // 2.5 (bare reference in value position → the binding)
|
||||
x : s2 = 3; // bare `s2` in TYPE position is still the s2 int type
|
||||
```
|
||||
|
||||
A raw identifier is a value name and is **never a type**: using one in type
|
||||
position (`x : `s2 = 1`) is a parse error.
|
||||
**Type position.** A backtick in type position is the literal name used as a type
|
||||
reference: it resolves to a `` `s2 ``-declared type (struct / enum / union / type
|
||||
alias / …), and never the builtin. A bare `s2` in type position stays the builtin
|
||||
int; a backtick name with no matching declaration is a normal `unknown type 's2'`
|
||||
error.
|
||||
|
||||
The escape works in **every identifier position** — local, global, parameter,
|
||||
struct field, function name, a later reference, and every control-flow / capture /
|
||||
binding form: a destructure name, an `if` / `while` optional binding, a `for`
|
||||
capture and index, a match-arm capture, and a `catch` / `onfail` tag binding:
|
||||
```sx
|
||||
`s2 :: struct { x: s64; } // declare a type whose name is a reserved spelling
|
||||
v : `s2 = ---; // reference it as a type — resolves to the struct
|
||||
v.x = 7;
|
||||
x : s2 = 3; // bare `s2` is still the 2-bit signed int
|
||||
```
|
||||
|
||||
**Declaration position.** A *bare* reserved-name declaration of every kind still
|
||||
errors (a value binding, a `::` constant / function, and a `::` type / alias /
|
||||
protocol / foreign-class / ufcs / namespaced-import name); the backtick form is
|
||||
exempt. The escape works in **every identifier position** — local, global,
|
||||
parameter, struct field, union tag, function name, type/alias/import name, a later
|
||||
reference, and every control-flow / capture / binding form (destructure name,
|
||||
`if` / `while` optional binding, `for` capture and index, match-arm capture, and a
|
||||
`catch` / `onfail` tag binding):
|
||||
|
||||
```sx
|
||||
`u8 := 100; // global
|
||||
`s2 :: 2.5; // constant declaration
|
||||
`s2 : s64 : 5; // typed constant declaration
|
||||
`u8 :: (`s1: s64) -> s64 { `s1 } // function name + parameter
|
||||
P :: struct { `s2: f64; } // struct field
|
||||
M :: union { `s1: s32; } // union tag
|
||||
`u16 :: enum { A; B; } // type-declaration name
|
||||
`u8, rest := pair(); // destructure name
|
||||
if `s16 := maybe() { } // optional binding
|
||||
for xs: (`bool, `u16) { } // for capture + index
|
||||
@@ -73,8 +88,8 @@ x catch `s2 { } // catch tag binding
|
||||
```
|
||||
|
||||
A reserved-spelled **function** is bare-callable: `` `s2 :: (n: s64) -> s64 { … } ``
|
||||
can be invoked as `s2(10)` (the callee spelling parses as a type but resolves to
|
||||
the function when one of that name is in scope; `TypeName(val)` is not a cast).
|
||||
can be invoked as `s2(10)` (the bare callee spelling parses as a type but resolves
|
||||
to the function when one of that name is in scope; `TypeName(val)` is not a cast).
|
||||
|
||||
A backtick may also escape a keyword spelling (`` `for ``, `` `struct ``), yielding
|
||||
an identifier with that text.
|
||||
|
||||
Reference in New Issue
Block a user