From a3b1570a33c7cdca7db43efd3d2848d791bf386a Mon Sep 17 00:00:00 2001
From: LunaStev
Date: Mon, 7 Sep 2026 18:45:39 +0900
Subject: [PATCH] Remove unrequested language specification and dedicated
checks
Signed-off-by: LunaStev
---
CONTRIBUTING.md | 4 -
README.md | 3 -
front/lexer/src/token.rs | 2 +-
front/parser/tests/alpha_frontend.rs | 2 +-
front/parser/tests/grammar_contract.rs | 94 ---------------
spec/README.md | 151 -------------------------
spec/alpha-0.ebnf | 89 ---------------
spec/fixtures.tsv | 13 ---
spec/fixtures/aliases.accept.wave | 1 -
spec/fixtures/aliases.reject.wave | 1 -
spec/fixtures/control.accept.wave | 1 -
spec/fixtures/control.reject.wave | 1 -
spec/fixtures/enums.accept.wave | 1 -
spec/fixtures/enums.reject.wave | 1 -
spec/fixtures/expressions.accept.wave | 1 -
spec/fixtures/expressions.reject.wave | 1 -
spec/fixtures/ffi.accept.wave | 1 -
spec/fixtures/ffi.reject.wave | 1 -
spec/fixtures/functions.accept.wave | 2 -
spec/fixtures/functions.reject.wave | 1 -
spec/fixtures/imports.accept.wave | 1 -
spec/fixtures/imports.reject.wave | 1 -
spec/fixtures/io_asm.accept.wave | 1 -
spec/fixtures/io_asm.reject.wave | 1 -
spec/fixtures/matching.accept.wave | 1 -
spec/fixtures/matching.reject.wave | 1 -
spec/fixtures/numbers.accept.wave | 1 -
spec/fixtures/numbers.reject.wave | 1 -
spec/fixtures/records.accept.wave | 2 -
spec/fixtures/records.reject.wave | 1 -
spec/fixtures/variants.accept.wave | 1 -
spec/fixtures/variants.reject.wave | 1 -
spec/tokens.tsv | 110 ------------------
33 files changed, 2 insertions(+), 492 deletions(-)
delete mode 100644 front/parser/tests/grammar_contract.rs
delete mode 100644 spec/README.md
delete mode 100644 spec/alpha-0.ebnf
delete mode 100644 spec/fixtures.tsv
delete mode 100644 spec/fixtures/aliases.accept.wave
delete mode 100644 spec/fixtures/aliases.reject.wave
delete mode 100644 spec/fixtures/control.accept.wave
delete mode 100644 spec/fixtures/control.reject.wave
delete mode 100644 spec/fixtures/enums.accept.wave
delete mode 100644 spec/fixtures/enums.reject.wave
delete mode 100644 spec/fixtures/expressions.accept.wave
delete mode 100644 spec/fixtures/expressions.reject.wave
delete mode 100644 spec/fixtures/ffi.accept.wave
delete mode 100644 spec/fixtures/ffi.reject.wave
delete mode 100644 spec/fixtures/functions.accept.wave
delete mode 100644 spec/fixtures/functions.reject.wave
delete mode 100644 spec/fixtures/imports.accept.wave
delete mode 100644 spec/fixtures/imports.reject.wave
delete mode 100644 spec/fixtures/io_asm.accept.wave
delete mode 100644 spec/fixtures/io_asm.reject.wave
delete mode 100644 spec/fixtures/matching.accept.wave
delete mode 100644 spec/fixtures/matching.reject.wave
delete mode 100644 spec/fixtures/numbers.accept.wave
delete mode 100644 spec/fixtures/numbers.reject.wave
delete mode 100644 spec/fixtures/records.accept.wave
delete mode 100644 spec/fixtures/records.reject.wave
delete mode 100644 spec/fixtures/variants.accept.wave
delete mode 100644 spec/fixtures/variants.reject.wave
delete mode 100644 spec/tokens.tsv
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4f4878ed..8e6a01e4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -215,10 +215,6 @@ Contributors should:
---
-Frontend syntax changes must update [the Alpha grammar and token inventory](spec/README.md)
-and its positive/negative fixtures. Run `cargo test --locked -p lexer -p parser --jobs 2`
-for backend-independent frontend tests, then the workspace tests for driver and codegen coverage.
-
## 9. Pull Request Guidelines
A PR should include:
diff --git a/README.md b/README.md
index b4321b0b..d320c279 100644
--- a/README.md
+++ b/README.md
@@ -231,6 +231,3 @@ Wave is developed in public with support from individuals and organizations. You
Thank you to everyone who contributes code, documentation, testing, funding, or time to Wave.
-
-The [Alpha language contract](spec/README.md) defines the grammar, numeric literals,
-token status and source-location conventions checked by frontend conformance tests.
diff --git a/front/lexer/src/token.rs b/front/lexer/src/token.rs
index 8489eb8a..a3691641 100644
--- a/front/lexer/src/token.rs
+++ b/front/lexer/src/token.rs
@@ -198,7 +198,7 @@ pub enum TokenType {
}
impl TokenType {
- /// Reserved spellings have no executable Alpha grammar production.
+ /// These reserved spellings are not implemented.
pub fn reserved_spelling(&self) -> Option<&'static str> {
match self {
Self::Module => Some("module"),
diff --git a/front/parser/tests/alpha_frontend.rs b/front/parser/tests/alpha_frontend.rs
index 56a5ed1e..55eab808 100644
--- a/front/parser/tests/alpha_frontend.rs
+++ b/front/parser/tests/alpha_frontend.rs
@@ -1,4 +1,4 @@
-//! Alpha grammar regressions: malformed source must never be silently accepted.
+//! Parser regressions: malformed source must never be silently accepted.
use lexer::Lexer;
use parser::ast::{ASTNode, Expression, Literal};
use parser::generics::monomorphize_generics;
diff --git a/front/parser/tests/grammar_contract.rs b/front/parser/tests/grammar_contract.rs
deleted file mode 100644
index 199c0868..00000000
--- a/front/parser/tests/grammar_contract.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-//! Normative grammar fixtures and complete token-inventory drift detection.
-use lexer::Lexer;
-use parser::parse_syntax_with_spans;
-use std::collections::BTreeSet;
-use std::path::Path;
-
-#[test]
-fn every_token_kind_is_classified_and_its_example_matches_the_lexer() {
- let vocabulary = include_str!("../../lexer/src/token.rs")
- .split("pub enum TokenType {")
- .nth(1)
- .unwrap()
- .split("\n}")
- .next()
- .unwrap();
- let variants: BTreeSet<_> = vocabulary
- .lines()
- .filter_map(|line| {
- let line = line.trim();
- if line.starts_with("//") || line.is_empty() {
- return None;
- }
- Some(line.split(['(', ',']).next().unwrap())
- })
- .collect();
- let grammar = include_str!("../../../spec/alpha-0.ebnf");
- let productions: BTreeSet<_> = grammar
- .lines()
- .filter_map(|line| line.split_once(" = ").map(|p| p.0))
- .collect();
- let mut documented = BTreeSet::new();
- for row in include_str!("../../../spec/tokens.tsv")
- .lines()
- .filter(|line| !line.starts_with('#'))
- {
- let fields: Vec<_> = row.split('\t').collect();
- assert_eq!(fields.len(), 5, "{row}");
- assert!(
- documented.insert(fields[0]),
- "duplicate token {}",
- fields[0]
- );
- assert!(
- matches!(
- fields[1],
- "implemented" | "reserved" | "removed" | "internal"
- ),
- "{row}"
- );
- assert!(productions.contains(fields[3]), "{row}");
- if fields[4] != "-" {
- let tokens = Lexer::new(fields[4]).tokenize().unwrap();
- assert_eq!(tokens.len(), 2, "{row}: {tokens:?}");
- if fields[1] == "reserved" {
- assert!(tokens[0].token_type.reserved_spelling().is_some(), "{row}");
- for body in [format!("{};", fields[4]), format!("1 {} 2;", fields[4])] {
- let source = format!("fun f() {{ {body} }}");
- let tokens = Lexer::new(&source).tokenize().unwrap();
- assert!(parse_syntax_with_spans(&tokens).is_err(), "{source}");
- }
- }
- let actual = format!("{:?}", tokens[0].token_type);
- assert_eq!(actual.split('(').next().unwrap(), fields[0], "{row}");
- }
- }
- assert_eq!(
- variants, documented,
- "update spec/tokens.tsv when changing the token vocabulary"
- );
-}
-
-#[test]
-fn grammar_examples_accept_and_reject_as_documented() {
- let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../spec");
- let grammar = include_str!("../../../spec/alpha-0.ebnf");
- for row in include_str!("../../../spec/fixtures.tsv")
- .lines()
- .filter(|line| !line.starts_with('#'))
- {
- let (name, productions) = row.split_once('\t').unwrap();
- for production in productions.split(',') {
- assert!(grammar.contains(&format!("{production} = ")));
- }
- for (verdict, accept) in [("accept", true), ("reject", false)] {
- let file = root.join("fixtures").join(format!("{name}.{verdict}.wave"));
- let source = std::fs::read_to_string(&file).unwrap();
- let result = Lexer::new_with_file(&source, file.display().to_string())
- .tokenize()
- .map_err(|e| format!("{e:?}"))
- .and_then(|tokens| parse_syntax_with_spans(&tokens).map_err(|e| format!("{e:?}")));
- assert_eq!(result.is_ok(), accept, "{}: {result:?}", file.display());
- }
- }
-}
diff --git a/spec/README.md b/spec/README.md
deleted file mode 100644
index e20e733a..00000000
--- a/spec/README.md
+++ /dev/null
@@ -1,151 +0,0 @@
-# Wave Alpha language contract, revision 0
-
-[alpha-0.ebnf](alpha-0.ebnf) defines the source grammar implemented by this
-frontend. [tokens.tsv](tokens.tsv) inventories **every** `TokenType` variant,
-including internal compatibility variants, reserved syntax and removed syntax.
-This is a language contract revision, not a compiler release announcement.
-Changes to accepted syntax must update the grammar, inventory and conformance
-fixtures together. Correctness fixes to existing productions do not require a
-new language version.
-
-## Reading the grammar
-
-Quotes denote source terminals; commas concatenate; `|` chooses; brackets are
-optional; braces repeat zero or more times. `? ... ?` is a lexical condition
-specified here. Longest-token matching applies before parsing. For example,
-`--x` is decrement, while `- -x` is two unary negations. A token cannot be split
-by whitespace or comments. Types such as `i64` are single tokens, despite their
-spelling being factored in `integer-type`. Generic closing chevrons are split
-contextually from `>>` by the generic parser.
-
-Whitespace, CRLF/LF newlines, `//` comments and `/* ... */` comments separate
-tokens and do not terminate statements. Block comments do not nest. All local
-variables, expression statements, returns, breaks, continues and I/O statements
-require `;`, even immediately before `}`. Block constructs do not require `;`;
-standalone `asm` accepts one optional trailing `;`. Empty statements are not
-part of this grammar. A failed statement never permits the parser to skip its
-remaining tokens and resume silently.
-
-Assignment is right associative. Other binary operators and repeated casts
-associate left to right. Precedence from low to high is assignment, `||`, `&&`,
-`|`, `^`, binary `&`, equality, comparison, shift, addition, multiplication,
-`as`, prefix operators, postfix operators and primary expressions. Address-of
-uses the same `&` token as bitwise AND. `deref` is the dereference operator;
-prefix `*` is not supported. Conditions reject assignment and mutation in the
-semantic pass, even when their expression syntax is otherwise valid.
-
-An unparenthesized match subject ends at the first `{`; parenthesize subjects
-containing a record literal. Match arm bodies are blocks. Integer and enum
-patterns match scalar subjects. Variant patterns may recursively bind payloads;
-a bare name in a payload position binds a variable, while a qualified name
-selects a case. `_` is a wildcard. Arms permit a single optional `,` or `;`
-separator. Duplicate arms, duplicate bindings and nonexhaustive variant matches
-are semantic errors.
-
-## Names and declarations
-
-Identifiers start with a Unicode Alphabetic scalar or `_` and continue with
-Unicode Alphabetic or Numeric scalars or `_` (Rust's Unicode predicates).
-No normalization is performed: different scalar sequences are different names.
-Combining marks outside these predicates are not identifier characters.
-Keywords in the inventory cannot be identifiers. `bool`, `void`, `ptr` and
-`array` are contextual type spellings represented by identifier tokens.
-Reserved syntax (`module`, `class`, `is`, `xnand`, `~^`, `!&`, `!|`, `?`, `??`,
-`?:`) has no accepted production. `let` and `mut` declarations were removed;
-use `var`. Ranges, for-in loops, propagation operators, unsafe blocks, function
-pointer types, slices, destructuring, expression-valued if/match and match
-guards are not added by this revision.
-
-`pub` controls module visibility and is separate from the C ABI export
-attribute. `main` must remain private and nongeneric. Imports use
-`import("path" as alias);` or `import("path")::{name, other};`; aliases and
-selections cannot be combined. A public import requires explicit selections.
-`extern(c)` and `extern(system)` declare foreign functions; `export(c)` and
-`export(system)` define foreign entry points. These headers accept an optional
-string symbol. Extern parameters may omit their names, and a variadic marker
-must be last. Exported functions cannot be generic.
-
-The `#[target(...)]` attribute occupies its own source line and applies to one
-following declaration. Keys are `arch`, `os`, `env`, and `abi`, without repeated
-keys. The same filtering applies to imported sources and to variant declarations.
-Inactive declarations and attributes are replaced by spaces that preserve byte
-lengths and newline positions. Stacked target attributes and attributes inside
-bodies are outside this contract.
-
-Required parameters precede default parameters. Defaults are literal values
-(including signed numbers and null), not arbitrary constant expressions. Their
-values are checked against the declared type even if the function is never
-called. Parameter, payload and enum lists allow a trailing comma; calls, array
-literals and explicit type-argument lists do not. Generic parameter lists must
-be nonempty and contain unique names. `void` and `!` are restricted to return positions. `!` declares a function that
-cannot return: it must end in a provably endless loop or a call to another
-never-returning function (or an asm block declaring `clobber("noreturn")`). Explicit return statements are rejected in such functions.
-A never-returning call is allowed as a statement and terminates that control-flow
-path; this revision does not introduce bottom-type coercions in value expressions.
-`const` and `static` belong at top level. Field names, bindings, signatures,
-return coverage, visibility and ABI compatibility have additional semantic
-checks; syntactic acceptance is not a promise that a program is well typed.
-
-## Numbers and text
-
-Integers accept decimal, binary (`0b`/`0B`), octal (`0o`/`0O`) and hexadecimal
-(`0x`/`0X`). Every prefix requires digits. Exactly one underscore may appear
-between digits of the same numeric component. Decimal floats require a
-fractional part with digits on both sides of the point or a decimal exponent:
-`1.0`, `1e3`, `1_000.5e-2`. Exponent signs are allowed; number suffixes and
-hexadecimal floats are not. Thus `1.`, `.5`, `1__2`, `0x_1`, `0b102`, `1e+` and
-`1u32` are rejected. Invalid adjacent digit/identifier text is diagnosed as one
-malformed number, not separate valid tokens. A decimal point directly after a
-number belongs to that numeric token; use parentheses for postfix access on a
-numeric primary.
-
-Integer spelling and sign are preserved until a target type is known. Supported
-signed/unsigned widths are 8, 16, 32, 64, 128, 256, 512 and 1024. Decimal signed
-literals must fit the signed range; nondecimal positive literals may spell the
-full-width bit pattern. Negative signed minimum values are supported. Unsigned
-initializers cannot be negative. Explicit casts retain the existing conversion
-rules. Array lengths accept integer literals fitting `u32`. `isz` and `usz`
-remain symbolic in the AST, then resolve to the selected target's pointer
-width **before** semantic analysis and generic specialization: wasm32 uses 32;
-the supported native 64-bit targets and wasm64 use 64. Unsupported numeric
-width spellings are errors, not user-defined types.
-
-Floating literals are converted once to finite IEEE binary64 values; a literal
-with an expected f32 type must also fit finite binary32. Overflow is diagnosed;
-underflow may round to zero. Integer-to-float constant conversion accumulates
-exact integer digits before one rounded conversion. The shared implementation
-is `front/lexer/src/number.rs`; semantic checking and LLVM constants use it too.
-
-Strings contain Unicode scalar values and use UTF-8 when emitted. Supported
-string escapes are `\\`, `\"`, `\n`, `\t`, `\r`, and `\xNN`; the last denotes
-the scalar U+00NN. Character literals contain exactly one value in 0..255,
-matching Wave's 8-bit `char`; their escapes additionally include `\'`.
-`\0` is not an escape: use `\x00`. Physical newlines and unknown or incomplete
-escapes are rejected. Escaped strings retain their original source spelling
-and byte span separately from the decoded value.
-
-## Source provenance and conformance
-
-Locations use half-open UTF-8 byte ranges and one-based line/column coordinates;
-columns count Unicode scalars, not terminal cells or UTF-8 bytes. Parser-selected
-name spans focus declaration diagnostics. Imports retain their original file
-paths. Generic instances and inserted defaults retain definition locations and
-record their expansion reason. Synthetic nodes without a physical origin have
-no span, represented as null, rather than an invented location on line 1.
-
-`parse_syntax_with_spans` is the compiler's source-preserving entry point.
-`parse_syntax_only` is a compatibility API for consumers that explicitly discard
-locations. Typed HIR exposes stable declaration/statement, expression and pattern
-IDs with source-span accessors. The diagnostic renderer uses these spans directly;
-it does not search for matching text in the source again.
-
-[fixtures.tsv](fixtures.tsv) maps production families to positive and negative
-source files in [fixtures](fixtures/). `grammar_contract.rs` executes both sides
-and verifies that every token kind has exactly one inventory row referring to a
-real production. Lexical examples must produce the documented token kind.
-`numeric_contract.rs`, `alpha_frontend.rs` and `source_spans.rs` add detailed
-numeric, block, target-filter and provenance regressions. Linux CI runs the
-workspace tests, so frontend conformance runs independently of LLVM test filters.
-
-Run locally with `cargo test --locked -p lexer -p parser --jobs 2`; run compiler
-and backend integration with `cargo test --locked --workspace --all-targets --jobs 2`.
diff --git a/spec/alpha-0.ebnf b/spec/alpha-0.ebnf
deleted file mode 100644
index e07a8d68..00000000
--- a/spec/alpha-0.ebnf
+++ /dev/null
@@ -1,89 +0,0 @@
-(* Wave Alpha grammar contract, revision 0. See README.md for lexical and semantic constraints. *)
-program = { [ target-attribute ], declaration } ;
-target-attribute = "#[target(", target-key, "=", string, { ",", target-key, "=", string }, ")]" ;
-target-key = "arch" | "os" | "env" | "abi" ;
-declaration = [ "pub" ], ( function | structure | enumeration | variant | alias | global | import | export ) | extern | proto ;
-function = "fun", identifier, [ generic-parameters ], "(", [ parameters ], ")", [ "->", type ], block ;
-generic-parameters = "<", identifier, { ",", identifier }, [ "," ], ">" ;
-parameters = parameter, { ",", parameter }, [ "," ] ;
-parameter = identifier, ":", type, [ "=", default ] ;
-default = { "+" | "-" }, number | string | character | "true" | "false" | "null" ;
-structure = "struct", identifier, [ generic-parameters ], "{", { field | function }, "}" ;
-field = identifier, ":", type, ";" ;
-proto = "proto", identifier, "{", { function }, "}" ;
-enumeration = "enum", identifier, "->", type, "{", [ enum-cases ], "}" ;
-enum-cases = enum-case, { ",", enum-case }, [ "," ] ;
-enum-case = identifier, [ "=", { "+" | "-" }, integer ] ;
-variant = "variant", identifier, [ generic-parameters ], "{", [ variant-cases ], "}" ;
-variant-cases = variant-case, { ",", variant-case }, [ "," ] ;
-variant-case = identifier, [ "(", [ type, { ",", type }, [ "," ] ], ")" ] ;
-alias = "type", identifier, "=", type, ";" ;
-global = ( "const" | "static" ), identifier, ":", type, [ "=", expression ], ";" ;
-import = "import", "(", string, [ "as", identifier ], ")", [ "::", "{", identifier, { ",", identifier }, [ "," ], "}" ], ";" ;
-ffi-header = "(", identifier, [ ",", string ], ")" ;
-extern = "extern", ffi-header, ( extern-function | "{", { extern-function }, "}", [ ";" ] ) ;
-extern-function = "fun", identifier, "(", [ extern-parameters ], ")", [ "->", type ], ";" ;
-extern-parameters = extern-parameter, { ",", extern-parameter }, [ ",", ".", ".", "." | "," ] | ".", ".", "." ;
-extern-parameter = [ identifier, ":" ], type ;
-export = "export", ffi-header, ( function | "{", { function }, "}", [ ";" ] ) ;
-type = integer-type | float-type | "bool" | "char" | "byte" | "str" | "void" | "!" | "ptr", "<", type, ">" | "array", "<", type, ",", integer, ">" | qualified-name, [ type-arguments ] ;
-integer-type = "isz" | "usz" | ( "i" | "u" ), ( "8" | "16" | "32" | "64" | "128" | "256" | "512" | "1024" ) ;
-float-type = "f32" | "f64" ;
-type-arguments = "<", type, { ",", type }, ">" ;
-block = "{", { statement }, "}" ;
-statement = local | if | while | for | match | io | "return", [ expression ], ";" | ( "break" | "continue" ), ";" | asm, [ ";" ] | expression, ";" ;
-local = "var", identifier, ":", type, [ "=", expression ], ";" ;
-if = "if", "(", expression, ")", block, { "else", "if", "(", expression, ")", block }, [ "else", block ] ;
-while = "while", "(", expression, ")", block ;
-for = "for", "(", for-initializer, ";", expression, ";", expression, ")", block ;
-for-initializer = [ "var" ], identifier, ":", type, [ "=", expression ] | expression ;
-match = "match", ( "(", expression, ")" | expression ), "{", { match-arm, [ "," | ";" ] }, "}" ;
-match-arm = pattern, "=", ">", block ;
-pattern = [ "-" ], integer | qualified-name, [ "(", [ pattern, { ",", pattern } ], ")" ] | "_" ;
-io = ( "print" | "println" | "input" ), "(", string, { ",", expression }, ")", ";" ;
-expression = logical-or, [ assignment-operator, expression ] ;
-assignment-operator = "=" | "+=" | "-=" | "*=" | "/=" | "%=" ;
-logical-or = logical-and, { "||", logical-and } ;
-logical-and = bitwise-or, { "&&", bitwise-or } ;
-bitwise-or = bitwise-xor, { "|", bitwise-xor } ;
-bitwise-xor = bitwise-and, { "^", bitwise-and } ;
-bitwise-and = equality, { "&", equality } ;
-equality = relational, { ( "==" | "!=" ), relational } ;
-relational = shift, { ( "<" | "<=" | ">" | ">=" ), shift } ;
-shift = additive, { ( "<<" | ">>" ), additive } ;
-additive = multiplicative, { ( "+" | "-" ), multiplicative } ;
-multiplicative = cast, { ( "*" | "/" | "%" ), cast } ;
-cast = unary, { "as", type } ;
-unary = ( "+" | "-" | "!" | "~" | "&" | "deref" | "++" | "--" ), unary | postfix ;
-postfix = primary, { ".", identifier, [ arguments ] | "[", expression, "]" }, [ "++" | "--" ] ;
-primary = literal | "null" | "(", expression, ")" | "[", [ expression, { ",", expression } ], "]" | asm | qualified-name, [ type-arguments ], ( arguments | record-fields ) | qualified-name ;
-arguments = "(", [ expression, { ",", expression } ], ")" ;
-record-fields = "{", [ identifier, ":", expression, { ",", identifier, ":", expression }, [ "," ] ], "}" ;
-asm = "asm", "{", { string | asm-operand | clobber | "," | ";" }, "}" ;
-asm-operand = ( "in" | "out" ), "(", ( string | identifier ), ")", expression ;
-clobber = "clobber", "(", [ ( string | identifier ), { ",", ( string | identifier ) } ], ")" ;
-literal = number | string | character | "true" | "false" ;
-number = integer | float ;
-integer = decimal-integer | ( "0b" | "0B" ), binary-digits | ( "0o" | "0O" ), octal-digits | ( "0x" | "0X" ), hex-digits ;
-decimal-integer = decimal-digit, { [ "_" ], decimal-digit } ;
-binary-digits = binary-digit, { [ "_" ], binary-digit } ;
-octal-digits = octal-digit, { [ "_" ], octal-digit } ;
-hex-digits = hex-digit, { [ "_" ], hex-digit } ;
-float = decimal-integer, ( ".", decimal-integer, [ exponent ] | exponent ) ;
-exponent = ( "e" | "E" ), [ "+" | "-" ], decimal-integer ;
-qualified-name = identifier, { "::", identifier } ;
-identifier = identifier-start, { identifier-continue } ;
-identifier-start = ? Unicode Alphabetic scalar or underscore ? ;
-identifier-continue = ? Unicode Alphabetic or Numeric scalar or underscore ? ;
-decimal-digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
-binary-digit = "0" | "1" ;
-octal-digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" ;
-hex-digit = decimal-digit | "a" | "b" | "c" | "d" | "e" | "f" | "A" | "B" | "C" | "D" | "E" | "F" ;
-string = '"', { string-character | escape }, '"' ;
-character = "'", ( character-scalar | escape ), "'" ;
-escape = ? Backslash followed by n, t, r, backslash, matching quote or x and exactly two hex digits, as specified in README.md ? ;
-string-character = ? Unicode scalar except newline, backslash and double quote ? ;
-character-scalar = ? Exactly one accepted character scalar; see README.md for byte restriction ? ;
-reserved = "module" | "class" | "is" | "xnand" | "~^" | "!&" | "!|" | "?" | "??" | "?:" ;
-removed = "let" | "mut" ;
-internal = ? Token variants retained for parser/API compatibility; no standalone source spelling ? ;
diff --git a/spec/fixtures.tsv b/spec/fixtures.tsv
deleted file mode 100644
index f4f4208d..00000000
--- a/spec/fixtures.tsv
+++ /dev/null
@@ -1,13 +0,0 @@
-# name productions
-functions function,parameter,default,generic-parameters
-records structure,field,proto
-enums enumeration,enum-case
-variants variant,variant-case
-aliases alias,global,type
-imports import,declaration
-ffi extern,export,ffi-header,extern-function
-control block,statement,local,if,while,for
-matching match,match-arm,pattern
-expressions expression,assignment-operator,postfix,primary
-io_asm io,asm,asm-operand,clobber
-numbers number,integer,float,identifier,string,character
diff --git a/spec/fixtures/aliases.accept.wave b/spec/fixtures/aliases.accept.wave
deleted file mode 100644
index 46fba394..00000000
--- a/spec/fixtures/aliases.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-type Count = usz; const LIMIT: i128 = 0o20; static ptr_value: ptr = null;
diff --git a/spec/fixtures/aliases.reject.wave b/spec/fixtures/aliases.reject.wave
deleted file mode 100644
index 7b347225..00000000
--- a/spec/fixtures/aliases.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-type Bad = i24;
diff --git a/spec/fixtures/control.accept.wave b/spec/fixtures/control.accept.wave
deleted file mode 100644
index fa502ee6..00000000
--- a/spec/fixtures/control.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { var i: i32 = 0; if (true) { true; } else if (false) { !false; } else { +1; } while (i < 3) { i++; continue; } for (i: i32 = 0; i < 4; i++) { break; } return; }
diff --git a/spec/fixtures/control.reject.wave b/spec/fixtures/control.reject.wave
deleted file mode 100644
index db891109..00000000
--- a/spec/fixtures/control.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { while (true) { break } }
diff --git a/spec/fixtures/enums.accept.wave b/spec/fixtures/enums.accept.wave
deleted file mode 100644
index f4401262..00000000
--- a/spec/fixtures/enums.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-enum Code -> i32 { Zero, Negative = -1, Hex = 0x10, }
diff --git a/spec/fixtures/enums.reject.wave b/spec/fixtures/enums.reject.wave
deleted file mode 100644
index bb421d91..00000000
--- a/spec/fixtures/enums.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-enum Code -> i32 { Bad = "text" }
diff --git a/spec/fixtures/expressions.accept.wave b/spec/fixtures/expressions.accept.wave
deleted file mode 100644
index 0043d3c7..00000000
--- a/spec/fixtures/expressions.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { a = b = 1 + 2 * 3; a += 1; a.b[0]++; deref p; &a; ~a; a << 2; a >> 1; a & b ^ c | d; a < b && b != c || a == c; (1 as i64); [1, 2]; Box { value: 1 }; }
diff --git a/spec/fixtures/expressions.reject.wave b/spec/fixtures/expressions.reject.wave
deleted file mode 100644
index e81118ff..00000000
--- a/spec/fixtures/expressions.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { a() b(); }
diff --git a/spec/fixtures/ffi.accept.wave b/spec/fixtures/ffi.accept.wave
deleted file mode 100644
index c0c79d09..00000000
--- a/spec/fixtures/ffi.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-extern(c) { fun puts(str) -> i32; fun log(fmt: str, ...); } export(c, "entry") fun entry() {}
diff --git a/spec/fixtures/ffi.reject.wave b/spec/fixtures/ffi.reject.wave
deleted file mode 100644
index 49f4efd9..00000000
--- a/spec/fixtures/ffi.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-extern(c) fun bad(x i32);
diff --git a/spec/fixtures/functions.accept.wave b/spec/fixtures/functions.accept.wave
deleted file mode 100644
index 3a4541a1..00000000
--- a/spec/fixtures/functions.accept.wave
+++ /dev/null
@@ -1,2 +0,0 @@
-fun id(x: T) -> T { return x; }
-fun value(x: i32 = 0x10) -> i32 { return x; }
diff --git a/spec/fixtures/functions.reject.wave b/spec/fixtures/functions.reject.wave
deleted file mode 100644
index 4943b48e..00000000
--- a/spec/fixtures/functions.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun bad(x: i32 = 0x) {}
diff --git a/spec/fixtures/imports.accept.wave b/spec/fixtures/imports.accept.wave
deleted file mode 100644
index 29c8ba38..00000000
--- a/spec/fixtures/imports.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-import("std::bytes" as bytes); pub import("module")::{Thing, value};
diff --git a/spec/fixtures/imports.reject.wave b/spec/fixtures/imports.reject.wave
deleted file mode 100644
index e876fab5..00000000
--- a/spec/fixtures/imports.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-import("module")::{};
diff --git a/spec/fixtures/io_asm.accept.wave b/spec/fixtures/io_asm.accept.wave
deleted file mode 100644
index 1ea1ea00..00000000
--- a/spec/fixtures/io_asm.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { print("{}", 1); println("ok"); input("{}", &x); asm { "nop"; in("r") (&x as i64); out("r") x; clobber("memory"); } }
diff --git a/spec/fixtures/io_asm.reject.wave b/spec/fixtures/io_asm.reject.wave
deleted file mode 100644
index a190c1de..00000000
--- a/spec/fixtures/io_asm.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { asm { "nop" ? } }
diff --git a/spec/fixtures/matching.accept.wave b/spec/fixtures/matching.accept.wave
deleted file mode 100644
index 23312cc2..00000000
--- a/spec/fixtures/matching.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { match (value) { Option::Some(item) => { item; }, Option::None => { return; } } }
diff --git a/spec/fixtures/matching.reject.wave b/spec/fixtures/matching.reject.wave
deleted file mode 100644
index f9a2c7cc..00000000
--- a/spec/fixtures/matching.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { match (value) { _ => 1; } }
diff --git a/spec/fixtures/numbers.accept.wave b/spec/fixtures/numbers.accept.wave
deleted file mode 100644
index 5266b0ee..00000000
--- a/spec/fixtures/numbers.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun 숫자(x: f64 = 1_000.5e-2) { 0b10; 0o7; 0xFF; 1_000; "str\n"; 'a'; }
diff --git a/spec/fixtures/numbers.reject.wave b/spec/fixtures/numbers.reject.wave
deleted file mode 100644
index 3bd1c502..00000000
--- a/spec/fixtures/numbers.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-fun f() { 0b102; }
diff --git a/spec/fixtures/records.accept.wave b/spec/fixtures/records.accept.wave
deleted file mode 100644
index 349976f8..00000000
--- a/spec/fixtures/records.accept.wave
+++ /dev/null
@@ -1,2 +0,0 @@
-struct Box { value: T; fun get(self: ptr>) -> T { return self.value; } }
-proto Plain { fun f() {} }
diff --git a/spec/fixtures/records.reject.wave b/spec/fixtures/records.reject.wave
deleted file mode 100644
index 81bf5bfd..00000000
--- a/spec/fixtures/records.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-struct Bad { value: i32 }
diff --git a/spec/fixtures/variants.accept.wave b/spec/fixtures/variants.accept.wave
deleted file mode 100644
index 92378d34..00000000
--- a/spec/fixtures/variants.accept.wave
+++ /dev/null
@@ -1 +0,0 @@
-variant Option { None, Some(T), }
diff --git a/spec/fixtures/variants.reject.wave b/spec/fixtures/variants.reject.wave
deleted file mode 100644
index 3df7a14a..00000000
--- a/spec/fixtures/variants.reject.wave
+++ /dev/null
@@ -1 +0,0 @@
-variant Bad { Value(i32 i64) }
diff --git a/spec/tokens.tsv b/spec/tokens.tsv
deleted file mode 100644
index e913f2a1..00000000
--- a/spec/tokens.tsv
+++ /dev/null
@@ -1,110 +0,0 @@
-# TokenType status spellings production lexical example (- means internal/split token)
-Fun implemented fun function fun
-Extern implemented extern extern extern
-Export implemented export export export
-Pub implemented pub declaration pub
-Type implemented type alias type
-Enum implemented enum enumeration enum
-Variant implemented variant variant variant
-Static implemented static global static
-Var implemented var local var
-Let removed let removed let
-Mut removed mut removed mut
-Deref implemented deref unary deref
-Const implemented const global const
-If implemented if if if
-Else implemented else if else
-While implemented while while while
-For implemented for for for
-Import implemented import import import
-Return implemented return statement return
-Continue implemented continue statement continue
-Input implemented input io input
-Print implemented print io print
-Println implemented println io println
-Module reserved module reserved module
-Class reserved class reserved class
-Match implemented match match match
-LogicalAnd implemented && logical-and &&
-AddressOf implemented & bitwise-and &
-LogicalOr implemented || logical-or ||
-BitwiseOr implemented | bitwise-or |
-NotEqual implemented != equality !=
-Xor implemented ^ bitwise-xor ^
-Xnor reserved ~^ reserved ~^
-BitwiseNot implemented ~ unary ~
-Nand reserved !& reserved !&
-Nor reserved !| reserved !|
-Not implemented ! unary !
-Condition reserved ? reserved ?
-NullCoalesce reserved ?? reserved ??
-Conditional reserved ?: reserved -
-In implemented in asm-operand in
-Out implemented out asm-operand out
-Is reserved is reserved is
-As implemented as cast as
-Asm implemented asm asm asm
-Rol implemented << shift <<
-Ror implemented >> shift >>
-Xnand reserved xnand reserved xnand
-Operator internal - internal -
-TokenTypeInt implemented isz,i8,i16,i32,i64,i128,i256,i512,i1024 integer-type isz
-TokenTypeUint implemented usz,u8,u16,u32,u64,u128,u256,u512,u1024 integer-type usz
-TokenTypeFloat implemented f32,f64 float-type f32
-TypeInt internal - internal -
-TypeUint internal - internal -
-TypeFloat internal - internal -
-TypeBool internal bool (contextual identifier) internal -
-TypeChar implemented char type char
-TypeByte implemented byte type byte
-TypeString implemented str type str
-TypeCustom internal - internal -
-TypePointer internal - internal -
-TypeArray internal - internal -
-Identifier implemented ptr,array identifier sample_name
-String implemented "text" string "text"
-IntLiteral implemented 0x10 integer 0x10
-Float implemented 1.25e2 float 1.25e2
-Plus implemented + additive +
-Increment implemented ++ postfix ++
-PlusEq implemented += assignment-operator +=
-Minus implemented - additive -
-Decrement implemented -- postfix --
-MinusEq implemented -= assignment-operator -=
-Star implemented * multiplicative *
-StarEq implemented *= assignment-operator *=
-Div implemented / multiplicative /
-DivEq implemented /= assignment-operator /=
-Remainder implemented % multiplicative %
-RemainderEq implemented %= assignment-operator %=
-Equal implemented = assignment-operator =
-EqualTwo implemented == equality ==
-Comma implemented , parameters ,
-Dot implemented . postfix .
-SemiColon implemented ; block ;
-Colon implemented : parameters :
-DoubleColon implemented :: qualified-name ::
-Lchevr implemented < relational <
-LchevrEq implemented <= relational <=
-Rchevr implemented > relational >
-RchevrEq implemented >= relational >=
-Lparen implemented ( parameters (
-Rparen implemented ) parameters )
-Lbrace implemented { block {
-Rbrace implemented } block }
-Lbrack implemented [ postfix [
-Rbrack implemented ] postfix ]
-Eof internal - internal -
-Error internal - internal -
-Whitespace internal - internal -
-Break implemented break statement break
-Arrow implemented -> function ->
-Array internal - internal -
-Newline internal - internal -
-Proto implemented proto proto proto
-Struct implemented struct structure struct
-TypeVoid internal - internal -
-CharLiteral implemented 'a' character 'a'
-BoolLiteral implemented true,false literal true
-Null implemented null primary null
-Clobber implemented clobber clobber clobber