wesl 0.7.27 → 0.7.28

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 (61) hide show
  1. package/dist/index.d.ts +272 -126
  2. package/dist/index.js +1742 -1102
  3. package/package.json +1 -1
  4. package/src/AbstractElems.ts +263 -81
  5. package/src/Linker.ts +14 -2
  6. package/src/LinkerUtil.ts +141 -7
  7. package/src/LowerAndEmit.ts +660 -304
  8. package/src/ModuleResolver.ts +15 -4
  9. package/src/ParseWESL.ts +21 -33
  10. package/src/SrcMap.ts +7 -19
  11. package/src/debug/ASTtoString.ts +92 -76
  12. package/src/index.ts +1 -1
  13. package/src/parse/AttachComments.ts +289 -0
  14. package/src/parse/ExpressionUtil.ts +3 -3
  15. package/src/parse/ParseAttribute.ts +49 -71
  16. package/src/parse/ParseCall.ts +3 -4
  17. package/src/parse/ParseControlFlow.ts +100 -56
  18. package/src/parse/ParseDirective.ts +9 -8
  19. package/src/parse/ParseDoBlock.ts +63 -0
  20. package/src/parse/ParseExpression.ts +11 -10
  21. package/src/parse/ParseFn.ts +11 -33
  22. package/src/parse/ParseGlobalVar.ts +36 -27
  23. package/src/parse/ParseIdent.ts +4 -5
  24. package/src/parse/ParseLocalVar.ts +16 -12
  25. package/src/parse/ParseLoop.ts +76 -39
  26. package/src/parse/ParseModule.ts +65 -19
  27. package/src/parse/ParseSimpleStatement.ts +112 -66
  28. package/src/parse/ParseStatement.ts +39 -66
  29. package/src/parse/ParseStruct.ts +8 -22
  30. package/src/parse/ParseType.ts +10 -13
  31. package/src/parse/ParseUtil.ts +26 -12
  32. package/src/parse/ParseValueDeclaration.ts +18 -31
  33. package/src/parse/ParseWesl.ts +11 -14
  34. package/src/parse/ParsingContext.ts +11 -9
  35. package/src/parse/WeslStream.ts +138 -121
  36. package/src/parse/stream/RegexMatchers.ts +45 -0
  37. package/src/parse/stream/WeslLexer.ts +249 -0
  38. package/src/test/BevyLink.test.ts +17 -10
  39. package/src/test/ConditionalElif.test.ts +4 -2
  40. package/src/test/DeclCommentEmit.test.ts +122 -0
  41. package/src/test/DoBlock.test.ts +164 -0
  42. package/src/test/FilterValidElements.test.ts +4 -6
  43. package/src/test/Linker.test.ts +23 -7
  44. package/src/test/Mangling.test.ts +8 -4
  45. package/src/test/ParseComments.test.ts +234 -6
  46. package/src/test/ParseConditionsV2.test.ts +47 -175
  47. package/src/test/ParseElifV2.test.ts +12 -33
  48. package/src/test/ParseErrorV2.test.ts +0 -0
  49. package/src/test/ParseWeslV2.test.ts +247 -626
  50. package/src/test/StatementEmit.test.ts +143 -0
  51. package/src/test/StripWesl.ts +24 -3
  52. package/src/test/TestLink.ts +19 -3
  53. package/src/test/TestUtil.ts +18 -8
  54. package/src/test/Tokenizer.test.ts +96 -0
  55. package/src/test/__snapshots__/ParseWeslV2.test.ts.snap +10 -42
  56. package/src/RawEmit.ts +0 -103
  57. package/src/Reflection.ts +0 -336
  58. package/src/TransformBindingStructs.ts +0 -320
  59. package/src/parse/ContentsHelpers.ts +0 -70
  60. package/src/parse/stream/CachingStream.ts +0 -48
  61. package/src/parse/stream/MatchersStream.ts +0 -85
package/dist/index.d.ts CHANGED
@@ -58,17 +58,42 @@ interface TypedToken<Kind extends string> extends Token {
58
58
  //#region src/parse/WeslStream.d.ts
59
59
  type WeslTokenKind = "word" | "keyword" | "number" | "symbol";
60
60
  type WeslToken<Kind extends WeslTokenKind = WeslTokenKind> = TypedToken<Kind>;
61
+ /** A comment skipped by the tokenizer, recorded as leading trivia of the next token.
62
+ * Line-break flags (newline/blank before) are not stored here: they are derived
63
+ * on demand during comment attachment, so the tokenizer hot path never counts
64
+ * line breaks. */
65
+ interface CommentTrivia {
66
+ style: "line" | "block";
67
+ /** Source range of the comment text (excluding the trailing newline of a line comment). */
68
+ start: number;
69
+ end: number;
70
+ }
61
71
  /** A stream that produces WESL tokens, skipping over comments and white space */
62
72
  declare class WeslStream implements Stream<WeslToken> {
63
73
  private stream;
64
- /** New line */
74
+ /** New line (stateful: scanned via lastIndex, so kept per-instance). */
65
75
  private eolPattern;
66
76
  private blockCommentPattern;
77
+ /** Comments skipped before a real token, keyed by that token's start position. */
78
+ private triviaByPos;
79
+ /** Last peeked token, so the following nextToken() skips the rescan.
80
+ * Never invalidated: tokenization is deterministic per position. */
81
+ private peeked;
67
82
  src: string;
68
83
  constructor(src: string);
69
84
  checkpoint(): number;
70
85
  reset(position: number): void;
86
+ /** All recorded comment runs (each a contiguous group of comments between two
87
+ * real tokens), in source order. Consumed by the post-parse comment pass. */
88
+ commentRuns(): CommentTrivia[][];
89
+ private recordTrivia;
90
+ /** Next real token (comments/blankspace skipped and recorded as trivia); null at EOF. */
71
91
  nextToken(): WeslToken | null;
92
+ /** If the last peek() was at the current position, consume and return it. */
93
+ private usePeeked;
94
+ /** Skip a comment (rejecting embedded \0), advance the stream past it,
95
+ * and return it as trivia. */
96
+ private consumeComment;
72
97
  /** Peek at the next token without consuming it */
73
98
  peek(): WeslToken | null;
74
99
  /** Consume token if text matches, otherwise leave position unchanged */
@@ -79,7 +104,10 @@ declare class WeslStream implements Stream<WeslToken> {
79
104
  nextIf(predicate: (token: WeslToken) => boolean): WeslToken | null;
80
105
  /** Match a sequence of tokens by text. Resets and returns null if any fails. */
81
106
  matchSequence(...texts: string[]): WeslToken[] | null;
82
- private skipToEol;
107
+ /** End position of a comment opened by a commentStart token. */
108
+ private commentEnd;
109
+ /** End of a line comment: the start of the next line break (or end of file). */
110
+ private lineCommentEnd;
83
111
  private skipBlockComment;
84
112
  /**
85
113
  * Only matches the `<` token if it is a template
@@ -89,9 +117,14 @@ declare class WeslStream implements Stream<WeslToken> {
89
117
  nextTemplateStartToken(): (WeslToken & {
90
118
  kind: "symbol";
91
119
  }) | null;
120
+ /** Match a template-closing `>`, splitting it off a `>>`/`>=`/`>>=` token when needed. */
92
121
  nextTemplateEndToken(): (WeslToken & {
93
122
  kind: "symbol";
94
123
  }) | null;
124
+ /** Next symbol from the raw stream, skipping comment bodies (so symbols
125
+ * inside comments don't count) and non-symbol tokens; null at EOF. */
126
+ private nextRawSymbol;
127
+ /** Template-list discovery: scan forward from `<` for a balanced closing `>`. */
95
128
  private isTemplateStart;
96
129
  /**
97
130
  * Call this after consuming an opening bracket.
@@ -101,14 +134,17 @@ declare class WeslStream implements Stream<WeslToken> {
101
134
  }
102
135
  //#endregion
103
136
  //#region src/parse/ParsingContext.d.ts
137
+ /** Opt-in toggles for not-yet-spec'd WESL/WGSL features (for prototyping). */
138
+ interface WeslExtensions {
139
+ /** Parse `do name(...) { ... }` blocks. */
140
+ doBlocks?: boolean;
141
+ }
104
142
  interface ParseOptions {
105
- /** Store expression AST nodes in statement contents (for tooling/validation). */
106
- preserveExpressions?: boolean;
143
+ /** Enable parsing of experimental, not-yet-spec'd syntax extensions. */
144
+ weslExtensions?: WeslExtensions;
107
145
  }
108
146
  //#endregion
109
147
  //#region src/ParseWESL.d.ts
110
- /** Partial element being constructed during parsing. */
111
- type OpenElem<T extends ContainerElem = ContainerElem> = Pick<T, "kind" | "contents">;
112
148
  /**
113
149
  * Result of parsing one WESL module (e.g., one .wesl file).
114
150
  *
@@ -128,6 +164,8 @@ interface WeslAST {
128
164
  imports: ImportStatement[];
129
165
  /** Module level const_assert statements. */
130
166
  moduleAsserts?: ConstAssertElem[];
167
+ /** Parse options used to produce this AST (so re-parsing preserves them). */
168
+ parseOptions?: ParseOptions;
131
169
  }
132
170
  /** Extended AST with cached flattened imports. */
133
171
  interface BindingAST extends WeslAST {
@@ -144,7 +182,6 @@ type StableState = WeslAST;
144
182
  /** Unstable values used during parse collection. */
145
183
  interface WeslParseContext {
146
184
  scope: Scope;
147
- openElems: OpenElem[];
148
185
  }
149
186
  /** Human-readable error when parsing WESL fails. */
150
187
  declare class WeslParseError extends Error {
@@ -254,26 +291,38 @@ declare function childIdent(child: Scope | Ident): child is Ident;
254
291
  //#endregion
255
292
  //#region src/AbstractElems.d.ts
256
293
  /**
257
- * AST structures describing 'interesting' parts of WESL source.
258
- *
259
- * Parts needing further analysis are pulled into these structures.
260
- * Uninteresting parts are 'TextElem' nodes, copied to output WGSL.
294
+ * AST structures describing WESL source. Each element holds its interesting
295
+ * parts as typed child fields (name, type, init, body, ...); emit walks those
296
+ * fields and reconstructs the surrounding WGSL syntax rather than copying spans.
261
297
  */
262
- type AbstractElem = GrammarElem | SyntheticElem | ExpressionElem;
263
- type GrammarElem = ContainerElem | TerminalElem;
264
- type ContainerElem = AttributeElem | AliasElem | ConstAssertElem | ConstElem | ContinuingElem | UnknownExpressionElem | SimpleMemberRef | FnElem | TypedDeclElem | GlobalVarElem | LetElem | ModuleElem | OverrideElem | FnParamElem | StructElem | StructMemberElem | StuffElem | TypeRefElem | VarElem | StatementElem | SwitchClauseElem;
298
+ type AbstractElem = GrammarElem | SyntheticElem | ExpressionElem | UnknownExpressionElem;
299
+ type GrammarElem = ModuleElem | AttributeElem | Statement | SwitchClauseElem | AliasElem | GlobalVarElem | OverrideElem | StructElem | StructMemberElem | FnElem | FnParamElem | TypedDeclElem | TerminalElem | DoBlockElem;
265
300
  /** Map from element kind string to element type, for type-safe element construction. */
266
301
  type ElemKindMap = {
267
302
  alias: AliasElem;
268
303
  assert: ConstAssertElem;
304
+ block: BlockElem;
269
305
  const: ConstElem;
270
306
  continuing: ContinuingElem;
307
+ if: IfElem;
308
+ for: ForElem;
309
+ while: WhileElem;
310
+ loop: LoopElem;
311
+ switch: SwitchElem;
312
+ return: ReturnElem;
313
+ break: BreakElem;
314
+ continue: ContinueElem;
315
+ discard: DiscardElem;
316
+ assign: AssignElem;
317
+ increment: IncrementElem;
318
+ decrement: DecrementElem;
319
+ call: CallElem;
320
+ empty: EmptyElem;
271
321
  gvar: GlobalVarElem;
272
322
  let: LetElem;
273
323
  member: StructMemberElem;
274
324
  override: OverrideElem;
275
325
  param: FnParamElem;
276
- statement: StatementElem;
277
326
  struct: StructElem;
278
327
  "switch-clause": SwitchClauseElem;
279
328
  type: TypeRefElem;
@@ -281,26 +330,36 @@ type ElemKindMap = {
281
330
  };
282
331
  /** Inspired by https://github.com/webgpu-tools/wesl-rs/blob/3b2434eac1b2ebda9eb8bfb25f43d8600d819872/crates/wgsl-parse/src/syntax.rs#L364 */
283
332
  type ExpressionElem = Literal | RefIdentElem | TypeRefElem | ParenthesizedExpression | ComponentExpression | ComponentMemberExpression | UnaryExpression | BinaryExpression | FunctionCallExpression;
284
- type TerminalElem = DirectiveElem | DeclIdentElem | NameElem | RefIdentElem | TextElem | ImportElem;
285
- type GlobalDeclarationElem = AliasElem | ConstElem | FnElem | GlobalVarElem | OverrideElem | StructElem;
333
+ type TerminalElem = DirectiveElem | DeclIdentElem | NameElem | RefIdentElem | ImportElem;
334
+ type GlobalDeclarationElem = AliasElem | ConstElem | DoBlockElem | FnElem | GlobalVarElem | OverrideElem | StructElem;
286
335
  type DeclarationElem = GlobalDeclarationElem | FnParamElem | VarElem | LetElem;
287
336
  type ElemWithAttributes = Extract<AbstractElem, HasAttributes>;
288
337
  interface AbstractElemBase {
289
338
  kind: AbstractElem["kind"];
290
339
  start: number;
291
340
  end: number;
341
+ /** Comments leading this element (on their own line above it). */
342
+ commentsBefore?: CommentElem[];
343
+ /** Comments trailing this element (on the same line after it). */
344
+ commentsAfter?: CommentElem[];
292
345
  }
293
- interface ElemWithContentsBase extends AbstractElemBase {
294
- contents: AbstractElem[];
346
+ /**
347
+ * A source comment attached to an element as leading or trailing trivia.
348
+ * Not part of the {@link AbstractElem} union: comments are node metadata
349
+ * (in `commentsBefore` / `commentsAfter`), never `contents` children.
350
+ */
351
+ interface CommentElem {
352
+ kind: "comment";
353
+ style: "line" | "block";
354
+ start: number;
355
+ end: number;
356
+ srcModule: SrcModule;
357
+ /** Preserve one blank line above this comment (leading comments only). */
358
+ blankBefore?: boolean;
295
359
  }
296
360
  interface HasAttributes {
297
361
  attributes?: AttributeElem[];
298
362
  }
299
- /** Raw text copied to linked WGSL (e.g., 'var' or '@diagnostic(off,derivative_uniformity)'). */
300
- interface TextElem extends AbstractElemBase {
301
- kind: "text";
302
- srcModule: SrcModule;
303
- }
304
363
  /** A name that doesn't need to be an Ident (e.g., struct member, diagnostic rule). */
305
364
  interface NameElem extends AbstractElemBase {
306
365
  kind: "name";
@@ -351,20 +410,20 @@ interface SyntheticElem {
351
410
  text: string;
352
411
  }
353
412
  /** A declaration identifier with an optional type. */
354
- interface TypedDeclElem extends ElemWithContentsBase {
413
+ interface TypedDeclElem extends AbstractElemBase {
355
414
  kind: "typeDecl";
356
415
  decl: DeclIdentElem;
357
416
  typeRef?: TypeRefElem;
358
417
  typeScope?: Scope;
359
418
  }
360
419
  /** An alias statement. */
361
- interface AliasElem extends ElemWithContentsBase, HasAttributes {
420
+ interface AliasElem extends AbstractElemBase, HasAttributes {
362
421
  kind: "alias";
363
422
  name: DeclIdentElem;
364
423
  typeRef: TypeRefElem;
365
424
  }
366
425
  /** An attribute like '@compute' or '@binding(0)'. */
367
- interface AttributeElem extends ElemWithContentsBase {
426
+ interface AttributeElem extends AbstractElemBase {
368
427
  kind: "attribute";
369
428
  attribute: Attribute;
370
429
  }
@@ -401,23 +460,27 @@ interface ElseAttribute {
401
460
  }
402
461
  type ConditionalAttribute = IfAttribute | ElifAttribute | ElseAttribute;
403
462
  /** A const_assert statement. */
404
- interface ConstAssertElem extends ElemWithContentsBase, HasAttributes {
463
+ interface ConstAssertElem extends AbstractElemBase, HasAttributes {
405
464
  kind: "assert";
465
+ expression: ExpressionElem;
406
466
  }
407
467
  /** A const declaration. */
408
- interface ConstElem extends ElemWithContentsBase, HasAttributes {
468
+ interface ConstElem extends AbstractElemBase, HasAttributes {
409
469
  kind: "const";
410
470
  name: TypedDeclElem;
471
+ init?: ExpressionElem;
411
472
  }
412
473
  /** An expression without special handling, used in attribute parameters. */
413
- interface UnknownExpressionElem extends ElemWithContentsBase {
474
+ interface UnknownExpressionElem extends AbstractElemBase {
414
475
  kind: "expression";
476
+ expression: ExpressionElem;
415
477
  }
416
478
  /** An expression that can be safely evaluated at compile time. */
417
479
  interface TranslateTimeExpressionElem {
418
480
  kind: "translate-time-expression";
419
481
  expression: ExpressionElem;
420
- span: Span;
482
+ start: number;
483
+ end: number;
421
484
  }
422
485
  /** A literal value (boolean or number) in WESL source. */
423
486
  interface Literal extends AbstractElemBase {
@@ -458,13 +521,21 @@ interface BinaryExpression extends AbstractElemBase {
458
521
  interface FunctionCallExpression extends AbstractElemBase {
459
522
  kind: "call-expression";
460
523
  function: RefIdentElem | TypeRefElem;
524
+ /** Only populated for function calls; constructor calls carry templates on `function`. */
461
525
  templateArgs?: TypeTemplateParameter[];
462
526
  arguments: ExpressionElem[];
463
527
  }
464
528
  interface UnaryOperator {
465
529
  value: "!" | "&" | "*" | "-" | "~";
466
- span: Span;
530
+ start: number;
531
+ end: number;
467
532
  }
533
+ /** Uses span (not inline start/end) so each operator object stays in a smaller
534
+ * V8 size class. Inline start/end uses slightly less memory overall (no separate
535
+ * span tuple) but each object is bigger and more likely to be promoted to old
536
+ * gen under sustained allocation pressure, triggering more major GCs and
537
+ * ~5% slower wall time on math-heavy parse workloads (bevy_env_map/parse).
538
+ * A rare case where allocating more bytes wins on GC. */
468
539
  interface BinaryOperator {
469
540
  value: ("||" | "&&" | "+" | "-" | "*" | "/" | "%" | "==") | ("!=" | "<" | "<=" | ">" | ">=" | "|" | "&" | "^") | ("<<" | ">>");
470
541
  span: Span;
@@ -487,90 +558,198 @@ interface RequiresDirective {
487
558
  kind: "requires";
488
559
  extensions: NameElem[];
489
560
  }
561
+ /**
562
+ * A `do` block: a CPU-side dispatch script (`do name(params) { ... }`).
563
+ *
564
+ * Module-local: its name and body idents never enter bindIdents/the scope
565
+ * tree, and the linker drops it entirely from emitted WGSL. The parsed body
566
+ * is retained for the interpreter, which resolves names by AST match.
567
+ */
568
+ interface DoBlockElem extends AbstractElemBase, HasAttributes {
569
+ kind: "do";
570
+ name: NameElem;
571
+ params: FnParamElem[];
572
+ body: BlockElem;
573
+ }
490
574
  /** A function declaration. */
491
- interface FnElem extends ElemWithContentsBase, HasAttributes {
575
+ interface FnElem extends AbstractElemBase, HasAttributes {
492
576
  kind: "fn";
493
577
  name: DeclIdentElem;
494
578
  params: FnParamElem[];
495
- body: StatementElem;
579
+ body: BlockElem;
496
580
  returnAttributes?: AttributeElem[];
497
581
  returnType?: TypeRefElem;
498
582
  }
499
583
  /** A global variable declaration (at the root level). */
500
- interface GlobalVarElem extends ElemWithContentsBase, HasAttributes {
584
+ interface GlobalVarElem extends AbstractElemBase, HasAttributes {
501
585
  kind: "gvar";
502
586
  name: TypedDeclElem;
587
+ /** Address-space / access-mode enumerants, e.g. `<storage, read_write>`. */
588
+ template?: NameElem[];
589
+ init?: ExpressionElem;
503
590
  }
504
591
  /** An entire file. */
505
- interface ModuleElem extends ElemWithContentsBase {
592
+ interface ModuleElem extends AbstractElemBase {
506
593
  kind: "module";
594
+ /** Top-level children (imports, directives, declarations, and any synthetic
595
+ * vars added by transforms) in source order. */
596
+ decls: AbstractElem[];
507
597
  }
508
598
  /** An override declaration. */
509
- interface OverrideElem extends ElemWithContentsBase, HasAttributes {
599
+ interface OverrideElem extends AbstractElemBase, HasAttributes {
510
600
  kind: "override";
511
601
  name: TypedDeclElem;
602
+ init?: ExpressionElem;
512
603
  }
513
604
  /** A parameter in a function declaration. */
514
- interface FnParamElem extends ElemWithContentsBase, HasAttributes {
605
+ interface FnParamElem extends AbstractElemBase, HasAttributes {
515
606
  kind: "param";
516
607
  name: TypedDeclElem;
517
608
  }
518
- /** Simple struct references like `myStruct.bar` (for binding struct transforms). */
519
- interface SimpleMemberRef extends ElemWithContentsBase {
520
- kind: "memberRef";
521
- name: RefIdentElem;
522
- member: NameElem;
523
- extraComponents?: StuffElem;
524
- }
525
609
  /** A struct declaration. */
526
- interface StructElem extends ElemWithContentsBase, HasAttributes {
610
+ interface StructElem extends AbstractElemBase, HasAttributes {
527
611
  kind: "struct";
528
612
  name: DeclIdentElem;
529
613
  members: StructMemberElem[];
530
- bindingStruct?: true;
531
- }
532
- /** Generic container of other elements. */
533
- interface StuffElem extends ElemWithContentsBase {
534
- kind: "stuff";
535
- }
536
- /** A struct declaration marked as a binding struct. */
537
- interface BindingStructElem extends StructElem {
538
- bindingStruct: true;
539
- entryFn?: FnElem;
540
614
  }
541
615
  /** A member of a struct declaration. */
542
- interface StructMemberElem extends ElemWithContentsBase, HasAttributes {
616
+ interface StructMemberElem extends AbstractElemBase, HasAttributes {
543
617
  kind: "member";
544
618
  name: NameElem;
545
619
  typeRef: TypeRefElem;
546
- mangledVarName?: string;
547
620
  }
548
621
  type TypeTemplateParameter = ExpressionElem;
549
622
  /** A type reference like 'f32', 'MyStruct', or 'ptr<storage, array<f32>, read_only>'. */
550
- interface TypeRefElem extends ElemWithContentsBase {
623
+ interface TypeRefElem extends AbstractElemBase {
551
624
  kind: "type";
552
625
  name: RefIdent;
553
626
  templateParams?: TypeTemplateParameter[];
554
627
  }
555
628
  /** A variable declaration. */
556
- interface VarElem extends ElemWithContentsBase, HasAttributes {
629
+ interface VarElem extends AbstractElemBase, HasAttributes {
557
630
  kind: "var";
558
631
  name: TypedDeclElem;
632
+ /** Address-space / access-mode enumerants, e.g. `<storage, read_write>`. */
633
+ template?: NameElem[];
634
+ init?: ExpressionElem;
559
635
  }
560
- interface LetElem extends ElemWithContentsBase, HasAttributes {
636
+ interface LetElem extends AbstractElemBase, HasAttributes {
561
637
  kind: "let";
562
638
  name: TypedDeclElem;
563
- }
564
- interface StatementElem extends ElemWithContentsBase, HasAttributes {
565
- kind: "statement";
566
- }
567
- interface ContinuingElem extends ElemWithContentsBase, HasAttributes {
639
+ init?: ExpressionElem;
640
+ }
641
+ /** Any WGSL statement inside a function or block body. */
642
+ type Statement = BlockElem | IfElem | ForElem | WhileElem | LoopElem | ContinuingElem | SwitchElem | ReturnElem | BreakElem | ContinueElem | DiscardElem | AssignElem | IncrementElem | DecrementElem | CallElem | ConstAssertElem | EmptyElem | VarElem | LetElem | ConstElem;
643
+ /** A bare `;` statement. Emits nothing, but kept in the AST as a statement node. */
644
+ interface EmptyElem extends AbstractElemBase, HasAttributes {
645
+ kind: "empty";
646
+ }
647
+ /** A `{ ... }` compound statement. */
648
+ interface BlockElem extends AbstractElemBase, HasAttributes {
649
+ kind: "block";
650
+ body: Statement[];
651
+ /** Comments inside an otherwise empty block, with no statement to attach to. */
652
+ innerComments?: CommentElem[];
653
+ }
654
+ /** An if / else-if / else chain. `else` nests: else-if is an IfElem, plain else a BlockElem. */
655
+ interface IfElem extends AbstractElemBase, HasAttributes {
656
+ kind: "if";
657
+ condition: ExpressionElem;
658
+ body: BlockElem;
659
+ else?: IfElem | BlockElem;
660
+ }
661
+ /** A for loop. */
662
+ interface ForElem extends AbstractElemBase, HasAttributes {
663
+ kind: "for";
664
+ init?: ForInit;
665
+ condition?: ExpressionElem;
666
+ update?: ForUpdate;
667
+ body: BlockElem;
668
+ }
669
+ type ForInit = VarElem | LetElem | ConstElem | AssignElem | IncrementElem | DecrementElem | CallElem;
670
+ type ForUpdate = AssignElem | IncrementElem | DecrementElem | CallElem;
671
+ /** A while loop. */
672
+ interface WhileElem extends AbstractElemBase, HasAttributes {
673
+ kind: "while";
674
+ condition: ExpressionElem;
675
+ body: BlockElem;
676
+ }
677
+ /** A loop, optionally ending with a continuing block. */
678
+ interface LoopElem extends AbstractElemBase, HasAttributes {
679
+ kind: "loop";
680
+ body: BlockElem;
681
+ continuing?: ContinuingElem;
682
+ }
683
+ /** A continuing block, optionally ending with `break if expr`. */
684
+ interface ContinuingElem extends AbstractElemBase, HasAttributes {
568
685
  kind: "continuing";
569
- }
570
- /** Statement or continuing - used in loop body parsing. */
571
- type BlockStatement = StatementElem | ContinuingElem;
572
- interface SwitchClauseElem extends ElemWithContentsBase, HasAttributes {
686
+ body: BlockElem;
687
+ breakIf?: ExpressionElem;
688
+ }
689
+ /** A switch statement. */
690
+ interface SwitchElem extends AbstractElemBase, HasAttributes {
691
+ kind: "switch";
692
+ selector: ExpressionElem;
693
+ clauses: SwitchClauseElem[];
694
+ /** Attributes on the switch body, between the selector and `{`. */
695
+ bodyAttributes?: AttributeElem[];
696
+ }
697
+ /** A case or default clause. `"default"` sentinel marks the default selector. */
698
+ interface SwitchClauseElem extends AbstractElemBase, HasAttributes {
573
699
  kind: "switch-clause";
700
+ selectors: (ExpressionElem | "default")[];
701
+ body: BlockElem;
702
+ }
703
+ /** A return statement, with an optional value. */
704
+ interface ReturnElem extends AbstractElemBase, HasAttributes {
705
+ kind: "return";
706
+ value?: ExpressionElem;
707
+ }
708
+ /** A break statement, or `break if expr`. */
709
+ interface BreakElem extends AbstractElemBase, HasAttributes {
710
+ kind: "break";
711
+ condition?: ExpressionElem;
712
+ }
713
+ /** A continue statement. */
714
+ interface ContinueElem extends AbstractElemBase, HasAttributes {
715
+ kind: "continue";
716
+ }
717
+ /** A discard statement. */
718
+ interface DiscardElem extends AbstractElemBase, HasAttributes {
719
+ kind: "discard";
720
+ }
721
+ /** Assignment, compound assignment, or phony `_ = expr`. */
722
+ interface AssignElem extends AbstractElemBase, HasAttributes {
723
+ kind: "assign";
724
+ lhs: ExpressionElem | PhonyTarget;
725
+ op: AssignOp;
726
+ rhs: ExpressionElem;
727
+ }
728
+ /** `i++` */
729
+ interface IncrementElem extends AbstractElemBase, HasAttributes {
730
+ kind: "increment";
731
+ target: ExpressionElem;
732
+ }
733
+ /** `i--` */
734
+ interface DecrementElem extends AbstractElemBase, HasAttributes {
735
+ kind: "decrement";
736
+ target: ExpressionElem;
737
+ }
738
+ /** A bare function call statement. */
739
+ interface CallElem extends AbstractElemBase, HasAttributes {
740
+ kind: "call";
741
+ call: FunctionCallExpression;
742
+ }
743
+ /** The `_` discard target of a phony assignment; never enters the ident system. */
744
+ interface PhonyTarget {
745
+ kind: "phony";
746
+ span: Span;
747
+ }
748
+ /** An assignment operator. Uses a span tuple (not inline start/end) to match
749
+ * BinaryOperator's smaller V8 size class; see the note there. */
750
+ interface AssignOp {
751
+ value: ("=" | "+=" | "-=" | "*=" | "/=" | "%=") | ("&=" | "|=" | "^=" | "<<=" | ">>=");
752
+ span: Span;
574
753
  }
575
754
  //#endregion
576
755
  //#region src/SrcMap.d.ts
@@ -628,8 +807,6 @@ declare class SrcMapBuilder {
628
807
  addSynthetic(fragment: string, syntheticSource: string, srcStart: number, srcEnd: number): void;
629
808
  /** append a synthetic newline, mapped to previous source location */
630
809
  addNl(): void;
631
- /** copy a string fragment from the src to the destination string */
632
- addCopy(srcStart: number, srcEnd: number): void;
633
810
  /** return a SrcMap */
634
811
  static build(builders: SrcMapBuilder[]): SrcMap;
635
812
  }
@@ -787,6 +964,8 @@ interface RecordResolverOptions {
787
964
  packageName?: string;
788
965
  /** Debug path prefix for error messages */
789
966
  debugWeslRoot?: string;
967
+ /** Enable experimental, not-yet-spec'd syntax extensions while parsing. */
968
+ weslExtensions?: WeslExtensions;
790
969
  }
791
970
  /** Module resolver for in-memory source records. Lazy by default. */
792
971
  declare class RecordResolver implements BatchModuleResolver {
@@ -794,6 +973,7 @@ declare class RecordResolver implements BatchModuleResolver {
794
973
  readonly sources: Record<string, string>;
795
974
  readonly packageName: string;
796
975
  readonly debugWeslRoot: string;
976
+ readonly weslExtensions?: WeslExtensions;
797
977
  constructor(sources: Record<string, string>, options?: RecordResolverOptions);
798
978
  resolveModule(modulePath: string): WeslAST | undefined;
799
979
  private findSource;
@@ -874,9 +1054,13 @@ interface LinkParams {
874
1054
  constants?: Record<string, string | number>;
875
1055
  /** function to construct globally unique wgsl identifiers */
876
1056
  mangler?: ManglerFn;
1057
+ /** opt-in parsing of experimental, not-yet-spec'd syntax extensions.
1058
+ * Only applied to the local source resolver built from `weslSrc`; callers
1059
+ * that supply their own `resolver` must set it on that resolver. */
1060
+ weslExtensions?: WeslExtensions;
877
1061
  }
878
1062
  /** Project config for web components and tools. */
879
- type WeslProject = Pick<LinkParams, "weslSrc" | "rootModuleName" | "conditions" | "constants" | "libs" | "packageName"> & {
1063
+ type WeslProject = Pick<LinkParams, "weslSrc" | "rootModuleName" | "conditions" | "constants" | "libs" | "packageName" | "weslExtensions"> & {
880
1064
  /** Shader directory relative to project root (set by ?link from wesl.toml). */shaderRoot?: string;
881
1065
  };
882
1066
  /** Context passed to virtual library generators. */
@@ -1026,7 +1210,6 @@ declare function filterValidElements<T extends AbstractElem>(elements: readonly
1026
1210
  declare function astToString(elem: AbstractElem, indent?: number): string;
1027
1211
  /** @return string representation of an attribute (for test/debug) */
1028
1212
  declare function attributeToString(attr: Attribute): string;
1029
- declare function debugContentsToString(elem: StuffElem): string;
1030
1213
  //#endregion
1031
1214
  //#region src/debug/ScopeToString.d.ts
1032
1215
  /** A debugging print of the scope tree with identifiers in nested brackets */
@@ -1110,6 +1293,20 @@ declare function sanitizePackageName(npmName: string): string;
1110
1293
  */
1111
1294
  declare function npmNameVariations(sanitizedPath: string): Generator<string>;
1112
1295
  //#endregion
1296
+ //#region src/LinkerUtil.d.ts
1297
+ /** A module's top-level declarations of a given kind, narrowed to that elem type. */
1298
+ declare function declsOfKind<K extends AbstractElem["kind"]>(moduleElem: ModuleElem, kind: K): Extract<AbstractElem, {
1299
+ kind: K;
1300
+ }>[];
1301
+ /** Visit an elem and all its descendants, parent before children (pre-order). */
1302
+ declare function visitAst(elem: AbstractElem, visitor: (elem: AbstractElem) => void): void;
1303
+ /**
1304
+ * Child elems of any AST node: the typed structural fields (attributes plus
1305
+ * body / condition / decls / ...) in source order. Returns [] for leaf elems.
1306
+ */
1307
+ declare function childElems(elem: AbstractElem): readonly AbstractElem[];
1308
+ declare function identElemLog(identElem: DeclIdentElem | RefIdentElem, ...messages: any[]): void;
1309
+ //#endregion
1113
1310
  //#region src/Logging.d.ts
1114
1311
  /** base logger (can be overridden to a capturing logger for tests) */
1115
1312
  declare let log: (...data: any[]) => void;
@@ -1172,57 +1369,6 @@ declare function stdFn(name: string): boolean;
1172
1369
  /** return true if the name is for a built in enumerant */
1173
1370
  declare function stdEnumerant(name: string): boolean;
1174
1371
  //#endregion
1175
- //#region src/TransformBindingStructs.d.ts
1176
- declare function bindingStructsPlugin(): WeslJsPlugin;
1177
- /**
1178
- * Transform binding structures into binding variables by mutating the AST.
1179
- *
1180
- * First we find all the binding structs:
1181
- * . find all the structs in the module by filtering the moduleElem.contents
1182
- * . for each struct:
1183
- * . mark any structs with that contain @group or @binding annotations as 'binding structs' and save them in a list
1184
- * . (later) create reverse links from structs to struct members
1185
- * . (later) visit all the binding structs and traverse to referencing structs, marking the referencing structs as binding structs too
1186
- * Generate synethic AST nodes for binding variables
1187
- *
1188
- * Find all references to binding struct members
1189
- * . find the componound idents by traversing moduleElem.contents
1190
- * . filter to find the compound idents that refer to 'binding structs'
1191
- * . go from each ident to its declaration,
1192
- * . declaration to typeRef reference
1193
- * . typeRef to type declaration
1194
- * . check type declaration to see if it's a binding struct
1195
- * . record the intermediate declaration (e.g. a fn param b:Bindings from 'fn(b:Bindings)' )
1196
- * rewrite references to binding struct members as synthetic elements
1197
- *
1198
- * Remove the binding structs from the AST
1199
- * Remove the intermediate fn param declarations from the AST
1200
- * Add the new binding variables to the AST
1201
- *
1202
- * @return the binding structs and the mutated AST
1203
- */
1204
- declare function lowerBindingStructs(ast: TransformedAST): TransformedAST;
1205
- declare function markEntryTypes(moduleElem: ModuleElem, bindingStructs: BindingStructElem[]): void;
1206
- /** mutate the AST, marking StructElems as bindingStructs
1207
- * (if they contain ptrs with @group @binding annotations)
1208
- * @return the binding structs
1209
- */
1210
- declare function markBindingStructs(moduleElem: ModuleElem): BindingStructElem[];
1211
- /** convert each member of the binding struct into a synthetic global variable */
1212
- declare function transformBindingStruct(s: StructElem, globalNames: Set<string>): SyntheticElem[];
1213
- interface MemberRefToStruct extends StructTrace {
1214
- memberRef: SimpleMemberRef;
1215
- }
1216
- interface StructTrace {
1217
- struct: StructElem;
1218
- intermediates: DeclarationElem[];
1219
- }
1220
- /** find all simple member references in the module that refer to binding structs */
1221
- declare function findRefsToBindingStructs(moduleElem: ModuleElem): MemberRefToStruct[];
1222
- /** Mutate the member reference elem to instead contain synthetic elem text.
1223
- * The new text is the mangled var name of the struct member that the memberRef refers to. */
1224
- declare function transformBindingReference(memberRef: SimpleMemberRef, struct: StructElem): SyntheticElem;
1225
- //#endregion
1226
1372
  //#region src/Util.d.ts
1227
1373
  declare function multiKeySet<A, B, V>(m: Map<A, Map<B, V>>, a: A, b: B, v: V): void;
1228
1374
  /** replace strings in a text according to a relacement map
@@ -1267,4 +1413,4 @@ declare function offsetToLineNumber(offset: number, text: string): [lineNum: num
1267
1413
  */
1268
1414
  declare function errorHighlight(source: string, span: Span): [string, string];
1269
1415
  //#endregion
1270
- export { AbstractElem, AbstractElemBase, AliasElem, Attribute, AttributeElem, BatchModuleResolver, BinaryExpression, BinaryOperator, BindIdentsParams, BindResults, BindingAST, BindingStructElem, BlockStatement, BoundAndTransformed, BuiltinAttribute, BundleResolver, ComponentExpression, ComponentMemberExpression, CompositeResolver, ConditionalAttribute, Conditions, ConstAssertElem, ConstElem, ContainerElem, ContinuingElem, DeclIdent, DeclIdentElem, DeclarationElem, DiagnosticAttribute, DiagnosticDirective, DiagnosticRule, DirectiveElem, DirectiveVariant, ElemKindMap, ElemWithAttributes, ElemWithContentsBase, ElifAttribute, ElseAttribute, EmittableElem, EnableDirective, ExpressionElem, ExtendedGPUValidationError, FnElem, FnParamElem, FunctionCallExpression, GlobalDeclarationElem, GlobalVarElem, GrammarElem, HasAttributes, Ident, IfAttribute, ImportCollection, ImportElem, ImportItem, ImportSegment, ImportStatement, InterpolateAttribute, LetElem, LexicalScope, LinkConfig, LinkParams, LinkRegistryParams, LinkedWesl, LinkerTransform, Literal, LiveDecls, ManglerFn, ModuleElem, ModuleResolver, NameElem, OpenElem, OverrideElem, ParenthesizedExpression, ParseError, type ParseOptions, PartialScope, RecordResolver, RecordResolverOptions, RefIdent, RefIdentElem, RequiresDirective, Scope, ScopeItem, SimpleMemberRef, Span, SrcMap, SrcMapBuilder, SrcMapEntry, SrcModule, SrcPosition, SrcWithPath, StableState, StandardAttribute, StatementElem, StructElem, StructMemberElem, StuffElem, SwitchClauseElem, SyntheticElem, TerminalElem, TextElem, TrackingResolver, TransformedAST, TranslateTimeExpressionElem, TypeRefElem, TypeTemplateParameter, TypedDeclElem, UnaryExpression, UnaryOperator, UnboundRef, UnknownExpressionElem, VarElem, VirtualLibContext, VirtualLibrary, VirtualLibraryFn, VirtualLibrarySet, WeslAST, WeslBundle, WeslDevice, WeslGPUCompilationInfo, WeslGPUCompilationMessage, WeslJsPlugin, WeslParseContext, WeslParseError, WeslParseState, WeslProject, WeslStream, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, bindingStructsPlugin, childIdent, childScope, containsScope, debug, debugContentsToString, discoverModules, emptyScope, errorHighlight, fileToModulePath, filterMap, filterValidElements, findAllRootDecls, findMap, findRefsToBindingStructs, findUnboundIdents, findUnboundRefs, findValidRootDecls, flatImports, freshResolver, groupBy, grouped, identToString, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, log, lowerBindingStructs, makeLiveDecls, makeWeslDevice, mapForward, mapValues, markBindingStructs, markEntryTypes, mergeScope, minimalMangle, minimallyMangledName, modulePartsToRelativePath, moduleToRelativePath, multiKeySet, multisampledTextureTypes, nextIdentId, noSuffix, normalize, normalizeDebugRoot, normalizeModuleName, npmNameVariations, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, resolveModulePath, sampledTextureTypes, sanitizePackageName, scan, scopeToString, scopeToStringLong, srcLog, stdEnumerant, stdEnumerants, stdFn, stdFns, stdType, stdTypes, textureStorageTypes, transformBindingReference, transformBindingStruct, underscoreMangle, validation, wgslStandardAttributes, withLoggerAsync };
1416
+ export { AbstractElem, AbstractElemBase, AliasElem, AssignElem, AssignOp, Attribute, AttributeElem, BatchModuleResolver, BinaryExpression, BinaryOperator, BindIdentsParams, BindResults, BindingAST, BlockElem, BoundAndTransformed, BreakElem, BuiltinAttribute, BundleResolver, CallElem, CommentElem, ComponentExpression, ComponentMemberExpression, CompositeResolver, ConditionalAttribute, Conditions, ConstAssertElem, ConstElem, ContinueElem, ContinuingElem, DeclIdent, DeclIdentElem, DeclarationElem, DecrementElem, DiagnosticAttribute, DiagnosticDirective, DiagnosticRule, DirectiveElem, DirectiveVariant, DiscardElem, DoBlockElem, ElemKindMap, ElemWithAttributes, ElifAttribute, ElseAttribute, EmittableElem, EmptyElem, EnableDirective, ExpressionElem, ExtendedGPUValidationError, FnElem, FnParamElem, ForElem, ForInit, ForUpdate, FunctionCallExpression, GlobalDeclarationElem, GlobalVarElem, GrammarElem, HasAttributes, Ident, IfAttribute, IfElem, ImportCollection, ImportElem, ImportItem, ImportSegment, ImportStatement, IncrementElem, InterpolateAttribute, LetElem, LexicalScope, LinkConfig, LinkParams, LinkRegistryParams, LinkedWesl, LinkerTransform, Literal, LiveDecls, LoopElem, ManglerFn, ModuleElem, ModuleResolver, NameElem, OverrideElem, ParenthesizedExpression, ParseError, type ParseOptions, PartialScope, PhonyTarget, RecordResolver, RecordResolverOptions, RefIdent, RefIdentElem, RequiresDirective, ReturnElem, Scope, ScopeItem, Span, SrcMap, SrcMapBuilder, SrcMapEntry, SrcModule, SrcPosition, SrcWithPath, StableState, StandardAttribute, Statement, StructElem, StructMemberElem, SwitchClauseElem, SwitchElem, SyntheticElem, TerminalElem, TrackingResolver, TransformedAST, TranslateTimeExpressionElem, TypeRefElem, TypeTemplateParameter, TypedDeclElem, UnaryExpression, UnaryOperator, UnboundRef, UnknownExpressionElem, VarElem, VirtualLibContext, VirtualLibrary, VirtualLibraryFn, VirtualLibrarySet, WeslAST, WeslBundle, WeslDevice, type WeslExtensions, WeslGPUCompilationInfo, WeslGPUCompilationMessage, WeslJsPlugin, WeslParseContext, WeslParseError, WeslParseState, WeslProject, WeslStream, WhileElem, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, childElems, childIdent, childScope, containsScope, debug, declsOfKind, discoverModules, emptyScope, errorHighlight, fileToModulePath, filterMap, filterValidElements, findAllRootDecls, findMap, findUnboundIdents, findUnboundRefs, findValidRootDecls, flatImports, freshResolver, groupBy, grouped, identElemLog, identToString, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, log, makeLiveDecls, makeWeslDevice, mapForward, mapValues, mergeScope, minimalMangle, minimallyMangledName, modulePartsToRelativePath, moduleToRelativePath, multiKeySet, multisampledTextureTypes, nextIdentId, noSuffix, normalize, normalizeDebugRoot, normalizeModuleName, npmNameVariations, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, resolveModulePath, sampledTextureTypes, sanitizePackageName, scan, scopeToString, scopeToStringLong, srcLog, stdEnumerant, stdEnumerants, stdFn, stdFns, stdType, stdTypes, textureStorageTypes, underscoreMangle, validation, visitAst, wgslStandardAttributes, withLoggerAsync };