Implements Phase 1 and 2 of the syntax rework plan: - Brackets `[]` are now mandatory for all tuple and array values. - Removed the `[Type][]` array syntax; arrays now only use `Type[]`. - `[single]` is now strictly a 1-tuple rather than an array. - Updated documentation and test fixtures to reflect these breaking changes.
5.5 KiB
Implementation Plan: Syntax Clarity & Parser Robustness
Status: In progress — Phases 1 & 2 applied (Phases 3–6 not yet done)
Goals
- Eliminate the backtracking heuristics in the value parser by making the value grammar context-free.
- Remove redundant/ambiguous syntax forms.
- Make union resolution deterministic and structural (not error-message-driven).
- Address the
csv-parsequote conflict. - Keep the
;separator (forced by CSV constraints — not the source of ambiguity).
All changes are breaking to the DSL → bump to 2.0.0, update README + csv-loader.md, add a migration note.
Phase 1 — Mandatory brackets for composite values ✅ Applied
Files: src/value-parser.ts, src/index.test.ts, src/csv-loader/reference-resolver.ts
- Removed the
allowOmitBracketsparameter fromparseValue,parseTupleValue,parseArrayValue. - Deleted the
elementIsTupleOrArraydisambiguation block and allsavedPosrestore logic inparseArrayValue. - Dropped the
allowOmitBrackets = schema.type === "tuple" || "array"special case in top-levelparseValue— brackets are always required. - Array references (
@table[]values) now also require brackets, for consistency. - Values must now be fully bracketed:
[a; 1]; [b; 2](no more[a; 1]; [b; 2]without outer brackets).
Decision: Full mandatory brackets (no carve-out).
Phase 2 — Single array form Type[] ✅ Applied
Files: src/parser.ts, src/index.test.ts
- Removed the
[Type][]array syntax fromparseSchemaInternal. Kept onlyType[]. [string]is now a 1-tuple (previously it collapsed to an array). The tuple branch always returns{ type: "tuple", elements }.- Updated
schemaToTypeStringinsrc/type-utils.ts— thearraycase no longer special-cases tuple elements; arrays are alwayselementType[](kept the(union)[]paren wrapping).
Tests updated: index.test.ts bracket-optional tests, encounter.csv / enemy_intents.csv fixtures, and parseCsv-typeDeclarations.test.ts array-of-tuple values.
Phase 3 — Deterministic union resolution
Files: src/csv-loader/reference-resolver.ts, src/validator.ts (via type-utils.ts), src/csv-loader/module-gen.ts
- Rule: In a union, always try non-reference members before reference members, regardless of author order. This makes fallback structural instead of error-message-driven.
- In
parseValueWithReferencesandresolveNestedReferences, replace the/not found|Circular reference|Failed to load/error-message inspection with a fixed ordering: partition members intononRef/ref, trynonReffirst, thenref. - In
module-gen.tsgenerateSchemaResolutionCodeunion case, apply the same ordering so generated code matches runtime behavior. - Document the rule in README (union member ordering is currently "first match wins" per AGENTS.md).
Note: This changes behavior for @users[] | string — string would now win for plain strings. Flag as a deliberate semantic change.
Phase 4 — Quote conflict resolution
Files: src/parser.ts, src/csv-loader/loader.ts, README, csv-loader.md
Options (pick one):
- (a) Standardize on single-quoted literals only — minimal change, but leaves a footgun.
- (b) Quote the entire schema cell so
csv-parsetreats it as one field — requires loader-side handling to strip the outer quotes before parsing. - (c) Drop quotes entirely — use bare-token literals (e.g.
on/offas identifiers). Most robust, largest change.
Recommendation: (b) — it's the only option that fixes the root cause (schema cells containing " break csv-parse) without redesigning the literal syntax. Requires: in loader.ts, detect schema-row cells that are fully quoted and unwrap before parseSchema.
Phase 5 — Cleanup & consistency
Files: src/csv-loader/reference-resolver.ts, src/csv-loader/loader.ts, src/csv-loader/module-gen.ts
- Reverse-reference performance:
resolveReverseReferencedoesrefTable.filter(...)per row. Build aMap<fk, rows[]>lookup once per referenced table (mirroring whatmodule-gen.tsalready generates) and reuse it. Cache the lookup alongside the parsed table inreferenceTableCache. - Remove the
,stop-character inparseReferenceValue(value parser has a,stop char the schema parser doesn't — drift). Make reference ID parsing consistent with the rest of the value grammar. int/float/number→number: document the collapse in README (type-level collapse is intentional; parse-time distinction remains).
Phase 6 — Docs & migration
Files: README.md, csv-loader.md, AGENTS.md
- Update all syntax tables and examples for mandatory brackets + single array form.
- Add a Migration section listing the breaking changes:
- Composite values must be fully bracketed.
[Type][]array form removed — useType[].[single]is now a 1-tuple, not an array.- Union resolution now prefers non-reference members.
- (If Phase 4b) schema cells may be fully quoted.
- Update
AGENTS.mdgotchas: union ordering rule, quote handling.
Validation
npm run typechecknpm run test(updatesrc/index.test.ts,src/csv-loader/*.test.tsfirst)- Manually verify the integration fixture (
user_rev.csv/order_rev.csv) still resolves.
Suggested execution order
Phases 1 → 2 are tightly coupled (both touch bracket parsing) — do them together. Phase 3 is independent. Phase 4 is independent. Phases 5–6 are cleanup/docs and can go last.