@words-lang/parser 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/analyser/analyser.d.ts +106 -0
  2. package/dist/analyser/analyser.d.ts.map +1 -0
  3. package/dist/analyser/analyser.js +291 -0
  4. package/dist/analyser/analyser.js.map +1 -0
  5. package/dist/analyser/diagnostics.d.ts +166 -0
  6. package/dist/analyser/diagnostics.d.ts.map +1 -0
  7. package/dist/analyser/diagnostics.js +139 -0
  8. package/dist/analyser/diagnostics.js.map +1 -0
  9. package/dist/analyser/workspace.d.ts +198 -0
  10. package/dist/analyser/workspace.d.ts.map +1 -0
  11. package/dist/analyser/workspace.js +403 -0
  12. package/dist/analyser/workspace.js.map +1 -0
  13. package/dist/index.d.ts +8 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +31 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/lexer/lexer.d.ts +120 -0
  18. package/dist/lexer/lexer.d.ts.map +1 -0
  19. package/dist/lexer/lexer.js +365 -0
  20. package/dist/lexer/lexer.js.map +1 -0
  21. package/dist/lexer/token.d.ts +247 -0
  22. package/dist/lexer/token.d.ts.map +1 -0
  23. package/dist/lexer/token.js +250 -0
  24. package/dist/lexer/token.js.map +1 -0
  25. package/dist/parser/ast.d.ts +685 -0
  26. package/dist/parser/ast.d.ts.map +1 -0
  27. package/dist/parser/ast.js +3 -0
  28. package/dist/parser/ast.js.map +1 -0
  29. package/dist/parser/parser.d.ts +411 -0
  30. package/dist/parser/parser.d.ts.map +1 -0
  31. package/dist/parser/parser.js +1600 -0
  32. package/dist/parser/parser.js.map +1 -0
  33. package/package.json +23 -0
  34. package/src/analyser/analyser.ts +403 -0
  35. package/src/analyser/diagnostics.ts +232 -0
  36. package/src/analyser/workspace.ts +457 -0
  37. package/src/index.ts +7 -0
  38. package/src/lexer/lexer.ts +379 -0
  39. package/src/lexer/token.ts +331 -0
  40. package/src/parser/ast.ts +798 -0
  41. package/src/parser/parser.ts +1815 -0
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/parser/ast.ts"],"names":[],"mappings":""}
@@ -0,0 +1,411 @@
1
+ /**
2
+ * parser.ts
3
+ *
4
+ * The WORDS parser. Consumes a flat token stream produced by the Lexer and
5
+ * builds an AST described in ast.ts.
6
+ *
7
+ * Design principles:
8
+ *
9
+ * - Recursive descent. Each grammar rule has a corresponding private method.
10
+ * Methods consume tokens and return AST nodes.
11
+ *
12
+ * - Error recovery. When an unexpected token is encountered the parser emits
13
+ * a diagnostic, skips tokens until it finds a safe synchronisation point
14
+ * (typically a newline, a closing paren, or a known top-level keyword), and
15
+ * continues. This means a single parse pass collects all errors in the file.
16
+ *
17
+ * - No exceptions for parse errors. All problems are collected in `this.diagnostics`
18
+ * and returned alongside the partial AST in the `ParseResult`.
19
+ *
20
+ * - Comments and newlines are consumed transparently by the `skip()` helper
21
+ * unless the calling rule explicitly needs them (e.g. ownership declaration
22
+ * detection requires newlines).
23
+ *
24
+ * - `system` and `state` are both keywords and identifier prefixes in access
25
+ * expressions (`system.setContext`, `state.context`). The parser disambiguates
26
+ * by context — inside a `uses` block or argument value position, these are
27
+ * treated as access expression roots, not construct keywords.
28
+ */
29
+ import { DocumentNode } from './ast';
30
+ import { Token } from '../lexer/token';
31
+ import { Diagnostic } from '../analyser/diagnostics';
32
+ /**
33
+ * The value returned by `Parser.parse()`.
34
+ * Always contains both a (possibly partial) document and all diagnostics
35
+ * collected during the parse — even when errors were encountered.
36
+ */
37
+ export interface ParseResult {
38
+ document: DocumentNode;
39
+ diagnostics: Diagnostic[];
40
+ }
41
+ export declare class Parser {
42
+ /** The full token stream from the lexer, including EOF. */
43
+ private tokens;
44
+ /** Current position in the token stream. */
45
+ private pos;
46
+ /** Diagnostics collected during this parse. */
47
+ private diagnostics;
48
+ constructor(tokens: Token[]);
49
+ /**
50
+ * Parses the entire token stream and returns a ParseResult containing
51
+ * the document AST and all collected diagnostics.
52
+ * Never throws — all errors are collected as diagnostics.
53
+ */
54
+ parse(): ParseResult;
55
+ /**
56
+ * Parses a complete `.wds` file.
57
+ *
58
+ * Detects the ownership declaration pattern — a bare `module ModuleName`
59
+ * on its own line at the top of component files. If the first non-trivial
60
+ * content is `module PascalIdent Newline` (with no opening `(`), it is
61
+ * captured as `ownerModule` and the next construct is parsed normally.
62
+ */
63
+ private parseDocument;
64
+ /**
65
+ * Parses one top-level construct and returns it, or emits a diagnostic
66
+ * and returns null if the current token does not start a known construct.
67
+ */
68
+ private parseTopLevel;
69
+ /**
70
+ * Parses:
71
+ * system SystemName "description" (
72
+ * modules ( ModuleOne ModuleTwo )
73
+ * interface ( ... )
74
+ * )
75
+ */
76
+ private parseSystem;
77
+ /**
78
+ * Parses:
79
+ * module ModuleName "description" (
80
+ * process ... ( when ... )
81
+ * start StateName
82
+ * implements Module.Handler ( methodName param(Type) ( if ... ) )
83
+ * system.Module.subscribeRoute ...
84
+ * interface HandlerName ( ... )
85
+ * )
86
+ */
87
+ private parseModule;
88
+ /**
89
+ * Parses:
90
+ * process ProcessName "description" (
91
+ * when State returns Context
92
+ * enter NextState "narrative"
93
+ * ...
94
+ * )
95
+ */
96
+ private parseProcess;
97
+ /**
98
+ * Parses:
99
+ * when CurrentState returns ProducedContext
100
+ * enter NextState "narrative" ( inlineContext? )
101
+ */
102
+ private parseWhenRule;
103
+ /**
104
+ * Parses an inline context construction block:
105
+ * ( reason is "..." code is "..." )
106
+ */
107
+ private parseInlineContext;
108
+ /**
109
+ * Parses:
110
+ * implements Module.HandlerInterface (
111
+ * methodName param(Type) (
112
+ * if param is "/path"
113
+ * enter State "narrative"
114
+ * )
115
+ * )
116
+ *
117
+ * The method name (e.g. `switch`) is a plain camelCase identifier chosen
118
+ * by the designer on the handler interface — it is not a reserved keyword.
119
+ */
120
+ private parseImplements;
121
+ /**
122
+ * Parses one branch inside an implements handler body:
123
+ * if param is "/path"
124
+ * enter State "narrative"
125
+ */
126
+ private parseImplementsBranch;
127
+ /**
128
+ * Parses:
129
+ * state StateName receives ?ContextName (
130
+ * returns ContextA, ContextB
131
+ * uses screen ScreenName
132
+ * )
133
+ */
134
+ private parseState;
135
+ /**
136
+ * Parses:
137
+ * context ContextName (
138
+ * field(Type),
139
+ * field(Type)
140
+ * )
141
+ */
142
+ private parseContext;
143
+ /**
144
+ * Parses:
145
+ * screen ScreenName "description" (
146
+ * uses ( ... )
147
+ * )
148
+ */
149
+ private parseScreen;
150
+ /**
151
+ * Parses:
152
+ * view ViewName "description" (
153
+ * props ( ... )
154
+ * state ( ... )
155
+ * uses ( ... )
156
+ * )
157
+ */
158
+ private parseView;
159
+ /**
160
+ * Parses:
161
+ * provider ProviderName "description" (
162
+ * props ( ... )
163
+ * state ( ... )
164
+ * interface ( methods... )
165
+ * )
166
+ */
167
+ private parseProvider;
168
+ /**
169
+ * Parses:
170
+ * adapter AdapterName "description" (
171
+ * props ( ... )
172
+ * state ( ... )
173
+ * interface ( methods... )
174
+ * )
175
+ */
176
+ private parseAdapter;
177
+ /**
178
+ * Parses:
179
+ * interface InterfaceName "description" (
180
+ * props ( ... )
181
+ * state ( ... )
182
+ * uses ( ... )
183
+ * methodName param(Type) returns(Type) "description"
184
+ * ...
185
+ * )
186
+ *
187
+ * When used as a module-level handler interface, the body contains a
188
+ * method declaration whose body is a series of `if` branches. The method
189
+ * name (e.g. `switch`) is a plain camelCase identifier — not a keyword.
190
+ */
191
+ private parseInterface;
192
+ /**
193
+ * Parses either the simple or expanded form of a returns clause.
194
+ *
195
+ * Simple: returns ContextA, ContextB
196
+ * Expanded: returns ( ContextA ( sideEffects ) ContextB ( sideEffects ) )
197
+ */
198
+ private parseReturns;
199
+ /**
200
+ * Parses a `uses` block and returns its entries.
201
+ * Handles both the single-entry form and the parenthesised list form.
202
+ *
203
+ * Single: `uses screen LoginScreen`
204
+ * List: `uses ( view A, view B, if ... )`
205
+ */
206
+ private parseUsesBlock;
207
+ /**
208
+ * Parses a comma-separated sequence of use entries inside a `uses ( ... )` block.
209
+ */
210
+ private parseUseEntries;
211
+ /**
212
+ * Parses a single use entry — a component use, a conditional block, or
213
+ * an iteration block.
214
+ */
215
+ private parseUseEntry;
216
+ /**
217
+ * Parses a single component use:
218
+ * view UIModule.LoginForm ( args... uses... )
219
+ * adapter SessionAdapter.checkSession
220
+ * screen LoginScreen
221
+ */
222
+ private parseComponentUse;
223
+ /**
224
+ * Parses:
225
+ * if condition ( useEntries... )
226
+ */
227
+ private parseConditionalBlock;
228
+ /**
229
+ * Parses:
230
+ * for collection as binding ( useEntries... )
231
+ * for collection as key, value ( useEntries... )
232
+ */
233
+ private parseIterationBlock;
234
+ /**
235
+ * Parses a condition expression:
236
+ * state.context is AccountDeauthenticated
237
+ * state.context.status is "pending"
238
+ * state.context is not AccountRecovered
239
+ */
240
+ private parseCondition;
241
+ /**
242
+ * Parses a comma-separated list of `name is value` arguments.
243
+ * Used inside parenthesised component use bodies and system calls.
244
+ */
245
+ private parseArguments;
246
+ /**
247
+ * Parses a comma-separated list of inline `name is value` arguments
248
+ * without an enclosing paren block. Stops at newline, `)`, or EOF.
249
+ */
250
+ private parseInlineArgList;
251
+ /**
252
+ * Parses a single argument: `name is value`
253
+ */
254
+ private parseArgument;
255
+ /**
256
+ * Parses an expression — a value on the right-hand side of an `is` assignment
257
+ * or a condition operand.
258
+ *
259
+ * Handles:
260
+ * - Block expressions: `( state.return(x) )`
261
+ * - state.return(): `state.return(contextName)`
262
+ * - Access expressions: `state.context.fullName`, `props.items`
263
+ * - Call expressions: `system.getContext(SystemUser)`
264
+ * - Literals: `"string"`, `42`, `3.14`, `true`, `false`, `[]`, `{}`
265
+ * - PascalCase type references: `SystemUser` (e.g. in system.getContext(SystemUser))
266
+ */
267
+ private parseExpression;
268
+ /**
269
+ * Parses a block expression: `( statements... )`
270
+ * The body contains either state.return() calls or assignment statements.
271
+ */
272
+ private parseBlockExpression;
273
+ /**
274
+ * Parses a statement inside a block expression body.
275
+ *
276
+ * `state.return(contextName)` → StateReturnStatement
277
+ * `state.fieldName is value` → AssignmentStatement
278
+ */
279
+ private parseStatement;
280
+ /**
281
+ * Parses an access expression or call expression starting with a camelCase
282
+ * name, 'state', or 'system'.
283
+ *
284
+ * If the path ends with `(...)`, it becomes a CallExpression.
285
+ * If the path ends with `return(...)`, it becomes a StateReturnExpression.
286
+ */
287
+ private parseAccessOrCall;
288
+ /**
289
+ * Parses a dot-separated access path — always returns an AccessExpressionNode.
290
+ * Used in conditions and iteration blocks where a call is not expected.
291
+ */
292
+ private parseAccessExpression;
293
+ private parseStringLiteral;
294
+ private parseIntegerLiteral;
295
+ private parseFloatLiteral;
296
+ private parseBooleanLiteral;
297
+ private parseListLiteral;
298
+ private parseMapLiteral;
299
+ /**
300
+ * Parses a comma-separated list of prop declarations inside a `props` or
301
+ * `state` or `context` block. Stops at `)` or EOF.
302
+ *
303
+ * Forms:
304
+ * `name(Type)` — typed data prop
305
+ * `name(Type) is default` — typed prop with default value
306
+ * `name argName(Type)` — interaction prop with argument variable
307
+ * `name` — interaction prop with no payload
308
+ * `?name(Type)` — optional typed prop (in context fields)
309
+ */
310
+ private parsePropList;
311
+ /**
312
+ * Parses a type annotation. Called when the cursor is on the type keyword or name.
313
+ */
314
+ private parseType;
315
+ /**
316
+ * Parses a standard method declaration in a provider, adapter, or interface body.
317
+ * Delegates to `parseInterfaceMethod` which also handles handler method bodies.
318
+ */
319
+ private parseMethod;
320
+ /**
321
+ * Parses a method declaration that may optionally have a body block of
322
+ * `if` branches — used for handler interface method declarations.
323
+ *
324
+ * Forms:
325
+ * `methodName "description"`
326
+ * `methodName param(Type) returns(Type) "description"`
327
+ * `methodName param(Type) ( if param is "/path" enter State "narrative" )`
328
+ */
329
+ private parseInterfaceMethod;
330
+ /**
331
+ * Parses a dot-separated qualified name.
332
+ * e.g. `UIModule.LoginForm`, `system.setContext`, `SessionAdapter.checkSession`
333
+ */
334
+ private parseQualifiedName;
335
+ /**
336
+ * Parses a literal value used as a default in a prop or state declaration.
337
+ * Handles strings, integers, floats, booleans, `[]`, and `{}`.
338
+ */
339
+ private parseLiteralValue;
340
+ /** Returns the token at the current position. */
341
+ private current;
342
+ /** Returns true if the current token has the given type. */
343
+ private check;
344
+ /**
345
+ * Consumes and returns the current token, advancing the position.
346
+ */
347
+ private advance;
348
+ /**
349
+ * Consumes the current token if it matches `type` and returns it.
350
+ * If it does not match, emits a diagnostic and returns null without advancing.
351
+ */
352
+ private expect;
353
+ /**
354
+ * Consumes a PascalIdent or CamelIdent and returns its value.
355
+ * Emits a diagnostic if neither is present.
356
+ */
357
+ private expectIdent;
358
+ /**
359
+ * Consumes and returns the string value if the current token is a StringLit.
360
+ * Returns null without advancing if it is not.
361
+ */
362
+ private parseOptionalString;
363
+ /**
364
+ * Skips comment tokens only.
365
+ */
366
+ private skipComments;
367
+ /**
368
+ * Skips comments and newlines — the whitespace between meaningful tokens.
369
+ */
370
+ private skipTrivia;
371
+ /**
372
+ * Returns true if the current token looks like a system.* call.
373
+ */
374
+ private checkSystemCall;
375
+ /**
376
+ * Returns true if the current token can start an argument (`name is value`).
377
+ * Arguments start with a camelCase identifier.
378
+ */
379
+ private checkArgumentStart;
380
+ /**
381
+ * Returns true if the current token can start a use entry (component kind,
382
+ * if, or for).
383
+ */
384
+ private isUseEntry;
385
+ /**
386
+ * Returns true if the current two tokens form a `[` `]` list literal.
387
+ * The lexer does not produce bracket tokens — `[]` is detected by checking
388
+ * for an Unknown token with value `[` followed by one with value `]`.
389
+ */
390
+ private checkListLiteral;
391
+ /**
392
+ * Returns true if the current two tokens form a `{` `}` map literal.
393
+ */
394
+ private checkMapLiteral;
395
+ /**
396
+ * Parses a system.* call expression appearing at the statement level
397
+ * (e.g. inside a module body or a uses block).
398
+ */
399
+ private parseSystemCall;
400
+ /**
401
+ * Emits a diagnostic at the given token's position.
402
+ */
403
+ private error;
404
+ /**
405
+ * Advances past tokens until a safe synchronisation point is found.
406
+ * Used after an unrecoverable parse error to resume at the next construct.
407
+ * Synchronisation points: top-level keyword, closing paren, or EOF.
408
+ */
409
+ private synchronise;
410
+ }
411
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"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"}