Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/docs/grammar-conformance.md

Grammar Conformance Plan

This document derives parser tests from the normative Syntactic Grammar. It does not define accepted source. If a case and the specification disagree, the specification wins and this plan must be corrected before implementation.

Test Layers

The source and syntax workspace keeps three distinct expectations:

  • parse: the token sequence has one grammar path and produces no syntax diagnostic
  • syntax reject: no complete production consumes the token sequence
  • semantic boundary: parsing succeeds, but the later declaration or checked-program phase must reject the program under the linked topical rule

Parser tests must not resolve a name, inspect a type, or invoke a semantic fallback to decide any of these expectations. Each accepted case also records a lossless syntax-tree snapshot so later error recovery cannot silently change its shape.

The implemented G001-G033 boundary has grouped accepted node-shape snapshots plus rejected and semantic-boundary source fixtures under development/compiler/tests/fixtures/syntax/. Focused unit cases exercise the individual optional, repeated, newline, ambiguity, and recovery branches inside those groups. Every future grammar production must add the same three fixture classes when it is introduced.

Declaration-owned G006-G010, G012-G013, and G015-G018 semantic cases also enter the production declaration-lowering facade in both forward and reversed package/module input order. The test compares the complete projected diagnostic, including its family, code, primary range, related ranges, messages, and help. G001, G005, G014, G011 conformance compatibility, and checked data/body validity remain assigned to their later semantic owners; the declaration facade does not guess those results.

Conformance Matrix

IDProduction coverageParse caseSyntax rejectionSemantic-boundary case
G001PackageFile, PackageDirective, directive records and fields#name: "p"#name: trueduplicate #name directives
G002ModuleSource, use/item sequencinguse ./helper before func run(): void {}a use after the functiona public item in an implementation source
G003visibility scopespub(../../) func run(): void {}pub(parser) func run(): void {}visibility wider than the declaration can expose
G004module paths, selections, aliases, and re-exportsuse /parser.{Parser, parse as parse_value,}use ./parser.{}an unresolved imported name
G005target attachment and targetable items#target: "arm64-darwin" followed by a function#target: "arm64-darwin" before test smoke {}an unsupported target name
G006functions, primitives, aliases, parameters, callable tails, provenance`func choose(left: &T, right: &T): &T from leftright`a function without : Resultan ineligible bodyless private function
G007structs, fields, enums, variants, payloadsenum Maybe<T> { some(value: T) missing } with newline-separated variantscomma-separated struct fieldsan empty enum body
G008interfaces and associated declarationsinterface Source { pub type Item pub method &+self.next(): Self.Item? } with member newlinesa non-public interface membera duplicate associated name
G009construction declarations, functions, and literalsconstruct Vec<T> { pub default func new(): Self { ... } }a construction member without visibilitytwo default members
G010instances, methods, coercions, and the four operator familiesan instance containing a method, coercion, equality, ordering, index, and expansion memberoperator (&self != other: &Self): bool { ... }an instance for a type outside its ownership boundary
G011conformances and associated bindingsconform Source for Input { type Item = u8 method &+self.next(): Self.Item? { ... } }pub method inside a conformancea method signature that disagrees with the interface
G012drop and native test declarationsdrop Buffer(&+self) {} and test empty {} as separate itemsvisibility on either declarationdrop for a non-owning or foreign type
G013scalar, named, selected, slice, fixed-array, grouped, pointer, and borrow types&parser.Buffer<T>.Item?[T; size]type arguments on an associated projection
G014outcome suffixes and nestingT?! and (T!)?T!?an outcome whose eventual payload is never
G015callable capabilities, named parameters, and provenance&+func(input: &T): &T from inputa callable type without a result annotationa provenance name that is not a parameter
G016opaque callable results and bindingsfunc values(): some Source<Item = u8>? { ... }func values(): some { ... }opaque syntax in a bodyless requirement
G017generic parameters, nested arguments, and split closersOuter<Inner<T>>an empty generic parameter listduplicate binders in struct Pair<T, T> {}
G018all requirement predicatesone clause containing capability, copy, equality, operator, coercion, and expansion predicatesa newline used instead of a predicate commaequality without an associated projection
G019blocks, block imports, executable sequences, and body results{ use std/io.print then a blank line then value }a block import after an executablea non-final non-void expression statement
G020bindings, annotations, assignment, and compound assignmentvar value: i32 = 1 followed by value += 2var value: i32 without an initializerassignment through an immutable place
G021return, break, continue, and explicit drop statementsreturn value, break, continue, and drop value in their legal containersdrop owner.fieldbreak outside a loop
G022while, loop, for-range, for-collection, region, and allocator placesfor index in 0..<count {} and region temp using allocators.arena {}a call as the allocator placeiteration over a value without expansion capability
G023if, if is, match, enum patterns, payload slots, and fallbackif value is Maybe.some(item) { item } else { fallback }a nested payload patternduplicate or non-final fallback arms
G024recovery, logical operators, and short-circuit levelsload() catch error { recover(error) } otherwise { fallback() }bare catch {}catch on a non-fallible value
G025equality, ordering, shifts, arithmetic, and conversions(left == right) == expected and &value as &Viewleft < middle < rightan operator without an applicable built-in or instance declaration
G026unary, move-place, and outcome expressions!ready, -count, &&value, and (move result?)?move make_value()moving a borrowed or already moved place
G027calls, members, and joint indexingfactory().field[index]value??calling a non-callable value
G028references, struct construction, fixed arrays, and qualified generic ownersparser.Buffer<T> { value: item } and Option<T>.some(item)explicit callable type arguments at an ordinary callconstructing a type with no accessible entry
G029typed sequence/string literals, spread, and allocation overridesVec [1, ...&source, ...move owned] using arenas.tempVec [...&+source]an override place that is not an allocation context
G030plain strings, interpolation, and literal-only strings"value: ${value}"String "value: ${value}"interpolating a value without formatting support
G031closures, captures, parameters, results, and grouping(&limit; value: i32): bool { value < limit }(; value) { value }an unlisted outer binding used by the closure
G032control-header brace boundaryif (Flags { ready: true }).ready {}if Flags { ready: true } {} as a struct-literal conditiona grouped closure used where bool is required
G033contextual spellings and removed formsfunc some(): i32 { 1 } and let copy = 1legacy alloc func and top-level trait formsSelf outside a type-owned semantic context

Ellipses in this planning table stand for an ordinary valid block body; fixture files will replace them with concrete tokens. A parser fixture must never use an ellipsis unless it is testing the actual expansion operator production.

Coverage Rule

Every grammar production belongs to the narrowest row that names it or its enclosing family. Before a parser production is implemented, that row is expanded into independent accepted, rejected, and semantic-boundary fixtures. Helper productions such as List, LineSequence, NamedPlace, and TypeSelectionSuffix receive direct boundary assertions inside every consuming family rather than one artificial top-level fixture.

The suite is complete only when every production has at least one successful edge, every optional or repeated branch has zero/one/many coverage as applicable, every joint/gap boundary is tested with both spaces and newlines, and every contextual spelling is tested both in and outside its special position.