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:
agra
2026-06-04 20:27:53 +03:00
parent c0e1a5db82
commit 023971cae5
26 changed files with 441 additions and 212 deletions

View File

@@ -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.