wesl 0.7.26 → 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.
- package/README.md +1 -1
- package/dist/index.d.ts +283 -147
- package/dist/index.js +1765 -1143
- package/package.json +2 -2
- package/src/AbstractElems.ts +264 -82
- package/src/ClickableError.ts +8 -1
- package/src/Linker.ts +63 -67
- package/src/LinkerUtil.ts +141 -7
- package/src/LowerAndEmit.ts +660 -304
- package/src/Mangler.ts +1 -1
- package/src/ModuleResolver.ts +15 -4
- package/src/ParseWESL.ts +21 -33
- package/src/SrcMap.ts +7 -19
- package/src/StandardTypes.ts +1 -1
- package/src/WeslDevice.ts +1 -0
- package/src/debug/ASTtoString.ts +92 -76
- package/src/index.ts +1 -1
- package/src/parse/AttachComments.ts +289 -0
- package/src/parse/ExpressionUtil.ts +3 -3
- package/src/parse/Keywords.ts +1 -1
- package/src/parse/ParseAttribute.ts +49 -71
- package/src/parse/ParseCall.ts +3 -4
- package/src/parse/ParseControlFlow.ts +100 -56
- package/src/parse/ParseDirective.ts +9 -8
- package/src/parse/ParseDoBlock.ts +63 -0
- package/src/parse/ParseExpression.ts +11 -10
- package/src/parse/ParseFn.ts +11 -33
- package/src/parse/ParseGlobalVar.ts +36 -27
- package/src/parse/ParseIdent.ts +4 -5
- package/src/parse/ParseLocalVar.ts +16 -12
- package/src/parse/ParseLoop.ts +76 -39
- package/src/parse/ParseModule.ts +65 -19
- package/src/parse/ParseSimpleStatement.ts +112 -66
- package/src/parse/ParseStatement.ts +40 -67
- package/src/parse/ParseStruct.ts +8 -22
- package/src/parse/ParseType.ts +10 -13
- package/src/parse/ParseUtil.ts +26 -12
- package/src/parse/ParseValueDeclaration.ts +18 -31
- package/src/parse/ParseWesl.ts +11 -14
- package/src/parse/ParsingContext.ts +11 -9
- package/src/parse/WeslStream.ts +138 -121
- package/src/parse/stream/RegexMatchers.ts +45 -0
- package/src/parse/stream/WeslLexer.ts +249 -0
- package/src/test/BevyLink.test.ts +18 -11
- package/src/test/ConditionalElif.test.ts +4 -2
- package/src/test/DeclCommentEmit.test.ts +122 -0
- package/src/test/DoBlock.test.ts +164 -0
- package/src/test/FilterValidElements.test.ts +4 -6
- package/src/test/Linker.test.ts +23 -7
- package/src/test/Mangling.test.ts +8 -4
- package/src/test/ParseComments.test.ts +234 -6
- package/src/test/ParseConditionsV2.test.ts +47 -175
- package/src/test/ParseElifV2.test.ts +12 -33
- package/src/test/ParseErrorV2.test.ts +0 -0
- package/src/test/ParseWeslV2.test.ts +247 -626
- package/src/test/StatementEmit.test.ts +143 -0
- package/src/test/StripWesl.ts +24 -3
- package/src/test/TestLink.ts +19 -3
- package/src/test/TestUtil.ts +18 -8
- package/src/test/Tokenizer.test.ts +96 -0
- package/src/test/__snapshots__/ParseWeslV2.test.ts.snap +10 -42
- package/src/RawEmit.ts +0 -103
- package/src/Reflection.ts +0 -336
- package/src/TransformBindingStructs.ts +0 -320
- package/src/parse/ContentsHelpers.ts +0 -70
- package/src/parse/stream/CachingStream.ts +0 -48
- package/src/parse/stream/MatchersStream.ts +0 -85
package/src/Mangler.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type ManglerFn = (
|
|
|
25
25
|
/**
|
|
26
26
|
* Construct a globally unique name based on the declaration
|
|
27
27
|
* module path separated by underscores.
|
|
28
|
-
* Corresponds to "Underscore-count mangling" from [NameMangling.md](https://github.com/
|
|
28
|
+
* Corresponds to "Underscore-count mangling" from [NameMangling.md](https://github.com/webgpu-tools/wesl-spec/blob/main/NameMangling.md)
|
|
29
29
|
*/
|
|
30
30
|
export function underscoreMangle(
|
|
31
31
|
decl: DeclIdent,
|
package/src/ModuleResolver.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { moduleToRelativePath, normalizeDebugRoot } from "./ModulePathUtil.ts";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
parseSrcModule,
|
|
4
|
+
type WeslAST,
|
|
5
|
+
type WeslExtensions,
|
|
6
|
+
} from "./ParseWESL.ts";
|
|
3
7
|
import { normalize, noSuffix } from "./PathUtil.ts";
|
|
4
8
|
import type { WeslBundle } from "./WeslBundle.ts";
|
|
5
9
|
|
|
@@ -20,6 +24,8 @@ export interface RecordResolverOptions {
|
|
|
20
24
|
packageName?: string;
|
|
21
25
|
/** Debug path prefix for error messages */
|
|
22
26
|
debugWeslRoot?: string;
|
|
27
|
+
/** Enable experimental, not-yet-spec'd syntax extensions while parsing. */
|
|
28
|
+
weslExtensions?: WeslExtensions;
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
const libRegex = /^lib\.w[eg]sl$/i;
|
|
@@ -30,15 +36,17 @@ export class RecordResolver implements BatchModuleResolver {
|
|
|
30
36
|
readonly sources: Record<string, string>;
|
|
31
37
|
readonly packageName: string;
|
|
32
38
|
readonly debugWeslRoot: string;
|
|
39
|
+
readonly weslExtensions?: WeslExtensions;
|
|
33
40
|
|
|
34
41
|
constructor(
|
|
35
42
|
sources: Record<string, string>,
|
|
36
43
|
options: RecordResolverOptions = {},
|
|
37
44
|
) {
|
|
38
|
-
const { packageName = "package", debugWeslRoot } = options;
|
|
45
|
+
const { packageName = "package", debugWeslRoot, weslExtensions } = options;
|
|
39
46
|
this.sources = sources;
|
|
40
47
|
this.packageName = packageName;
|
|
41
48
|
this.debugWeslRoot = normalizeDebugRoot(debugWeslRoot);
|
|
49
|
+
this.weslExtensions = weslExtensions;
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
resolveModule(modulePath: string): WeslAST | undefined {
|
|
@@ -49,7 +57,10 @@ export class RecordResolver implements BatchModuleResolver {
|
|
|
49
57
|
if (source === undefined) return undefined;
|
|
50
58
|
|
|
51
59
|
const debugFilePath = this.modulePathToDebugPath(modulePath);
|
|
52
|
-
const ast = parseSrcModule(
|
|
60
|
+
const ast = parseSrcModule(
|
|
61
|
+
{ modulePath, debugFilePath, src: source },
|
|
62
|
+
{ weslExtensions: this.weslExtensions },
|
|
63
|
+
);
|
|
53
64
|
this.astCache.set(modulePath, ast);
|
|
54
65
|
return ast;
|
|
55
66
|
}
|
|
@@ -171,7 +182,7 @@ export function freshResolver(inner: ModuleResolver): ModuleResolver {
|
|
|
171
182
|
if (cached) return cached;
|
|
172
183
|
const ast = inner.resolveModule(modulePath);
|
|
173
184
|
if (!ast) return undefined;
|
|
174
|
-
const fresh = parseSrcModule(ast.srcModule);
|
|
185
|
+
const fresh = parseSrcModule(ast.srcModule, ast.parseOptions);
|
|
175
186
|
cache.set(modulePath, fresh);
|
|
176
187
|
return fresh;
|
|
177
188
|
},
|
package/src/ParseWESL.ts
CHANGED
|
@@ -1,27 +1,18 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ConstAssertElem,
|
|
3
|
-
ContainerElem,
|
|
4
|
-
ImportElem,
|
|
5
3
|
ImportStatement,
|
|
6
4
|
ModuleElem,
|
|
7
5
|
} from "./AbstractElems.ts";
|
|
8
6
|
import { filterValidElements } from "./Conditions.ts";
|
|
9
7
|
import { type FlatImport, flattenTreeImport } from "./FlattenTreeImport.ts";
|
|
8
|
+
import { declsOfKind } from "./LinkerUtil.ts";
|
|
10
9
|
import type { ParseError } from "./ParseError.ts";
|
|
11
10
|
import { parseWesl } from "./parse/ParseWesl.ts";
|
|
12
|
-
import type { ParseOptions } from "./parse/ParsingContext.ts";
|
|
11
|
+
import type { ParseOptions, WeslExtensions } from "./parse/ParsingContext.ts";
|
|
13
12
|
import type { Conditions, Scope, SrcModule } from "./Scope.ts";
|
|
14
13
|
import type { Span } from "./Span.ts";
|
|
15
14
|
import { errorHighlight, offsetToLineNumber } from "./Util.ts";
|
|
16
15
|
|
|
17
|
-
export type { ParseOptions };
|
|
18
|
-
|
|
19
|
-
/** Partial element being constructed during parsing. */
|
|
20
|
-
export type OpenElem<T extends ContainerElem = ContainerElem> = Pick<
|
|
21
|
-
T,
|
|
22
|
-
"kind" | "contents"
|
|
23
|
-
>;
|
|
24
|
-
|
|
25
16
|
/**
|
|
26
17
|
* Result of parsing one WESL module (e.g., one .wesl file).
|
|
27
18
|
*
|
|
@@ -41,6 +32,8 @@ export interface WeslAST {
|
|
|
41
32
|
imports: ImportStatement[];
|
|
42
33
|
/** Module level const_assert statements. */
|
|
43
34
|
moduleAsserts?: ConstAssertElem[];
|
|
35
|
+
/** Parse options used to produce this AST (so re-parsing preserves them). */
|
|
36
|
+
parseOptions?: ParseOptions;
|
|
44
37
|
}
|
|
45
38
|
|
|
46
39
|
/** Extended AST with cached flattened imports. */
|
|
@@ -61,22 +54,25 @@ export type StableState = WeslAST;
|
|
|
61
54
|
/** Unstable values used during parse collection. */
|
|
62
55
|
export interface WeslParseContext {
|
|
63
56
|
scope: Scope; // current scope (points somewhere in rootScope)
|
|
64
|
-
openElems: OpenElem[]; // elems that are collecting their contents
|
|
65
57
|
}
|
|
66
58
|
|
|
59
|
+
export type { ParseOptions, WeslExtensions };
|
|
60
|
+
|
|
67
61
|
/** Human-readable error when parsing WESL fails. */
|
|
68
62
|
export class WeslParseError extends Error {
|
|
69
63
|
span: Span;
|
|
70
64
|
src: SrcModule;
|
|
71
65
|
constructor(opts: { cause: ParseError; src: SrcModule }) {
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
message
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
66
|
+
const { cause, src } = opts;
|
|
67
|
+
const source = src.src;
|
|
68
|
+
const [lineNum, linePos] = offsetToLineNumber(cause.span[0], source);
|
|
69
|
+
const highlight = errorHighlight(source, cause.span).join("\n");
|
|
70
|
+
const message =
|
|
71
|
+
`${src.debugFilePath}:${lineNum}:${linePos}` +
|
|
72
|
+
` error: ${cause.message}\n${highlight}`;
|
|
73
|
+
super(message, { cause });
|
|
74
|
+
this.span = cause.span;
|
|
75
|
+
this.src = src;
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
78
|
|
|
@@ -96,22 +92,14 @@ export function flatImports(
|
|
|
96
92
|
// TODO cache per condition set?
|
|
97
93
|
if (ast._flatImports && !conditions) return ast._flatImports;
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
const importElems = ast.moduleElem.contents.filter(
|
|
101
|
-
(elem): elem is ImportElem => elem.kind === "import",
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
// Filter based on conditions if provided
|
|
95
|
+
const importElems = declsOfKind(ast.moduleElem, "import");
|
|
105
96
|
const validImportElems = conditions
|
|
106
97
|
? filterValidElements(importElems, conditions)
|
|
107
98
|
: importElems;
|
|
108
99
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (!conditions) {
|
|
114
|
-
ast._flatImports = flat;
|
|
115
|
-
}
|
|
100
|
+
const flat = validImportElems.flatMap(elem =>
|
|
101
|
+
flattenTreeImport(elem.imports),
|
|
102
|
+
);
|
|
103
|
+
if (!conditions) ast._flatImports = flat;
|
|
116
104
|
return flat;
|
|
117
105
|
}
|
package/src/SrcMap.ts
CHANGED
|
@@ -88,14 +88,8 @@ export class SrcMap {
|
|
|
88
88
|
const { src, position: srcStart } = this.destToSrc(e.srcStart);
|
|
89
89
|
const { src: endSrc, position: srcEnd } = this.destToSrc(e.srcEnd);
|
|
90
90
|
if (endSrc !== src) throw new Error("NYI, need to split");
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
srcStart,
|
|
94
|
-
srcEnd,
|
|
95
|
-
destStart: e.destStart,
|
|
96
|
-
destEnd: e.destEnd,
|
|
97
|
-
};
|
|
98
|
-
return newEntry;
|
|
91
|
+
const { destStart, destEnd } = e;
|
|
92
|
+
return { src, srcStart, srcEnd, destStart, destEnd };
|
|
99
93
|
});
|
|
100
94
|
|
|
101
95
|
const otherSources = other.entries.filter(
|
|
@@ -122,11 +116,6 @@ export class SrcMap {
|
|
|
122
116
|
}
|
|
123
117
|
}
|
|
124
118
|
|
|
125
|
-
/** sort entries in place by src start position */
|
|
126
|
-
function sortSrc(entries: SrcMapEntry[]): void {
|
|
127
|
-
entries.sort((a, b) => a.srcStart - b.srcStart);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
119
|
/** Incrementally append to a string, tracking source references */
|
|
131
120
|
export class SrcMapBuilder {
|
|
132
121
|
#fragments: string[] = [];
|
|
@@ -191,12 +180,6 @@ export class SrcMapBuilder {
|
|
|
191
180
|
this.add("\n", srcStart, srcEnd);
|
|
192
181
|
}
|
|
193
182
|
|
|
194
|
-
/** copy a string fragment from the src to the destination string */
|
|
195
|
-
addCopy(srcStart: number, srcEnd: number): void {
|
|
196
|
-
const fragment = this.source.text.slice(srcStart, srcEnd);
|
|
197
|
-
this.add(fragment, srcStart, srcEnd);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
183
|
/** return a SrcMap */
|
|
201
184
|
static build(builders: SrcMapBuilder[]): SrcMap {
|
|
202
185
|
const map = new SrcMap(
|
|
@@ -207,3 +190,8 @@ export class SrcMapBuilder {
|
|
|
207
190
|
return map;
|
|
208
191
|
}
|
|
209
192
|
}
|
|
193
|
+
|
|
194
|
+
/** sort entries in place by src start position */
|
|
195
|
+
function sortSrc(entries: SrcMapEntry[]): void {
|
|
196
|
+
entries.sort((a, b) => a.srcStart - b.srcStart);
|
|
197
|
+
}
|
package/src/StandardTypes.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// From https://www.w3.org/TR/WGSL/#predeclared
|
|
2
|
-
// Use https://github.com/
|
|
2
|
+
// Use https://github.com/webgpu-tools/wgsl-spec to regenerate these list in the future
|
|
3
3
|
|
|
4
4
|
export const stdFns = `bitcast all any select arrayLength
|
|
5
5
|
abs acos acosh asin asinh atan atanh atan2 ceil clamp cos cosh
|
package/src/WeslDevice.ts
CHANGED
package/src/debug/ASTtoString.ts
CHANGED
|
@@ -2,15 +2,18 @@ import type {
|
|
|
2
2
|
AbstractElem,
|
|
3
3
|
Attribute,
|
|
4
4
|
AttributeElem,
|
|
5
|
+
CommentElem,
|
|
5
6
|
DirectiveElem,
|
|
7
|
+
DoBlockElem,
|
|
6
8
|
FnElem,
|
|
7
|
-
|
|
9
|
+
FnParamElem,
|
|
8
10
|
TypedDeclElem,
|
|
9
11
|
TypeRefElem,
|
|
10
12
|
TypeTemplateParameter,
|
|
11
13
|
UnknownExpressionElem,
|
|
12
14
|
} from "../AbstractElems.ts";
|
|
13
15
|
import { assertUnreachable } from "../Assertions.ts";
|
|
16
|
+
import { childElems } from "../LinkerUtil.ts";
|
|
14
17
|
import {
|
|
15
18
|
diagnosticControlToString,
|
|
16
19
|
expressionToString,
|
|
@@ -25,34 +28,38 @@ export function astToString(elem: AbstractElem, indent = 0): string {
|
|
|
25
28
|
const str = new LineWrapper(indent, maxLineLength);
|
|
26
29
|
str.add(kind);
|
|
27
30
|
addElemFields(elem, str);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
if (childStrings.length) {
|
|
31
|
+
addCommentFields(elem, str);
|
|
32
|
+
const children = childElems(elem);
|
|
33
|
+
if (children.length) {
|
|
33
34
|
str.nl();
|
|
35
|
+
const childStrings = children.map(e => astToString(e, indent + 2));
|
|
34
36
|
str.addBlock(childStrings.join("\n"), false);
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
return str.result;
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
/** @return string representation of an attribute (for test/debug) */
|
|
43
|
+
export function attributeToString(attr: Attribute): string {
|
|
44
|
+
const str = new LineWrapper(0, maxLineLength);
|
|
45
|
+
addAttributeFields(attr, str);
|
|
46
|
+
return str.result;
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
// LATER rewrite to be shorter and easier to read
|
|
41
50
|
function addElemFields(elem: AbstractElem, str: LineWrapper): void {
|
|
42
51
|
const { kind } = elem;
|
|
43
52
|
// no-op kinds (handled elsewhere or no additional fields)
|
|
44
53
|
if (
|
|
45
54
|
kind === "assert" ||
|
|
55
|
+
kind === "expression" ||
|
|
46
56
|
kind === "module" ||
|
|
47
57
|
kind === "param" ||
|
|
48
|
-
kind === "stuff" ||
|
|
49
58
|
kind === "switch-clause"
|
|
50
59
|
) {
|
|
51
60
|
return;
|
|
52
61
|
}
|
|
53
|
-
if (
|
|
54
|
-
str.add(` '${elem.srcModule.src.slice(elem.start, elem.end)}'`);
|
|
55
|
-
} else if (
|
|
62
|
+
if (
|
|
56
63
|
kind === "var" ||
|
|
57
64
|
kind === "let" ||
|
|
58
65
|
kind === "gvar" ||
|
|
@@ -68,13 +75,10 @@ function addElemFields(elem: AbstractElem, str: LineWrapper): void {
|
|
|
68
75
|
str.add(` ${elem.name.name}: ${typeRefElemToString(elem.typeRef)}`);
|
|
69
76
|
} else if (kind === "name") {
|
|
70
77
|
str.add(" " + elem.name);
|
|
71
|
-
} else if (kind === "memberRef") {
|
|
72
|
-
const extra = elem.extraComponents
|
|
73
|
-
? debugContentsToString(elem.extraComponents)
|
|
74
|
-
: "";
|
|
75
|
-
str.add(` ${elem.name.ident.originalName}.${elem.member.name}${extra}`);
|
|
76
78
|
} else if (kind === "fn") {
|
|
77
79
|
addFnFields(elem, str);
|
|
80
|
+
} else if (kind === "do") {
|
|
81
|
+
addDoFields(elem, str);
|
|
78
82
|
} else if (kind === "alias") {
|
|
79
83
|
const prefix = elem.name.ident.kind === "decl" ? "%" : "";
|
|
80
84
|
str.add(
|
|
@@ -82,20 +86,8 @@ function addElemFields(elem: AbstractElem, str: LineWrapper): void {
|
|
|
82
86
|
);
|
|
83
87
|
} else if (kind === "attribute") {
|
|
84
88
|
addAttributeFields(elem.attribute, str);
|
|
85
|
-
} else if (kind === "expression") {
|
|
86
|
-
const contents = elem.contents
|
|
87
|
-
.map(e =>
|
|
88
|
-
e.kind === "text"
|
|
89
|
-
? `'${e.srcModule.src.slice(e.start, e.end)}'`
|
|
90
|
-
: astToString(e),
|
|
91
|
-
)
|
|
92
|
-
.join(" ");
|
|
93
|
-
str.add(" " + contents);
|
|
94
89
|
} else if (kind === "type") {
|
|
95
|
-
|
|
96
|
-
typeof elem.name === "string" ? elem.name : elem.name.originalName;
|
|
97
|
-
const params = elem.templateParams?.map(templateParamToString).join(", ");
|
|
98
|
-
str.add(params ? ` ${nameStr}<${params}>` : ` ${nameStr}`);
|
|
90
|
+
str.add(" " + typeRefElemToString(elem));
|
|
99
91
|
} else if (kind === "synthetic") {
|
|
100
92
|
str.add(` '${elem.text}'`);
|
|
101
93
|
} else if (kind === "import") {
|
|
@@ -109,7 +101,25 @@ function addElemFields(elem: AbstractElem, str: LineWrapper): void {
|
|
|
109
101
|
str.add(" %" + elem.ident.originalName);
|
|
110
102
|
} else if (kind === "directive") {
|
|
111
103
|
addDirective(elem, str);
|
|
112
|
-
} else if (
|
|
104
|
+
} else if (
|
|
105
|
+
// statement kinds: the debug printer shows only their attributes
|
|
106
|
+
kind === "block" ||
|
|
107
|
+
kind === "if" ||
|
|
108
|
+
kind === "for" ||
|
|
109
|
+
kind === "while" ||
|
|
110
|
+
kind === "loop" ||
|
|
111
|
+
kind === "continuing" ||
|
|
112
|
+
kind === "switch" ||
|
|
113
|
+
kind === "return" ||
|
|
114
|
+
kind === "break" ||
|
|
115
|
+
kind === "continue" ||
|
|
116
|
+
kind === "discard" ||
|
|
117
|
+
kind === "assign" ||
|
|
118
|
+
kind === "increment" ||
|
|
119
|
+
kind === "decrement" ||
|
|
120
|
+
kind === "call" ||
|
|
121
|
+
kind === "empty"
|
|
122
|
+
) {
|
|
113
123
|
listAttributeElems(elem.attributes, str);
|
|
114
124
|
} else if (kind === "literal") {
|
|
115
125
|
str.add(` literal(${elem.value})`);
|
|
@@ -130,6 +140,18 @@ function addElemFields(elem: AbstractElem, str: LineWrapper): void {
|
|
|
130
140
|
}
|
|
131
141
|
}
|
|
132
142
|
|
|
143
|
+
/** Show attached leading/trailing comments to verify comment attachment. */
|
|
144
|
+
function addCommentFields(elem: AbstractElem, str: LineWrapper): void {
|
|
145
|
+
// SyntheticElem has no source position and so carries no comments
|
|
146
|
+
if (!("start" in elem)) return;
|
|
147
|
+
const { commentsBefore, commentsAfter } = elem;
|
|
148
|
+
if (commentsBefore?.length)
|
|
149
|
+
str.add(commentsToString("before", commentsBefore));
|
|
150
|
+
if (commentsAfter?.length) str.add(commentsToString("after", commentsAfter));
|
|
151
|
+
if ("innerComments" in elem && elem.innerComments?.length)
|
|
152
|
+
str.add(commentsToString("inner", elem.innerComments));
|
|
153
|
+
}
|
|
154
|
+
|
|
133
155
|
function addAttributeFields(attr: Attribute, str: LineWrapper) {
|
|
134
156
|
const { kind } = attr;
|
|
135
157
|
if (kind === "@attribute") {
|
|
@@ -155,13 +177,6 @@ function addAttributeFields(attr: Attribute, str: LineWrapper) {
|
|
|
155
177
|
}
|
|
156
178
|
}
|
|
157
179
|
|
|
158
|
-
/** @return string representation of an attribute (for test/debug) */
|
|
159
|
-
export function attributeToString(attr: Attribute): string {
|
|
160
|
-
const str = new LineWrapper(0, maxLineLength);
|
|
161
|
-
addAttributeFields(attr, str);
|
|
162
|
-
return str.result;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
180
|
function addTypedDeclIdent(elem: TypedDeclElem, str: LineWrapper) {
|
|
166
181
|
const { decl, typeRef } = elem;
|
|
167
182
|
str.add(" %" + decl.ident.originalName);
|
|
@@ -170,17 +185,6 @@ function addTypedDeclIdent(elem: TypedDeclElem, str: LineWrapper) {
|
|
|
170
185
|
}
|
|
171
186
|
}
|
|
172
187
|
|
|
173
|
-
function addFnFields(elem: FnElem, str: LineWrapper) {
|
|
174
|
-
const { name, params, returnType, attributes } = elem;
|
|
175
|
-
const paramStrs = params.map(p => {
|
|
176
|
-
const { originalName } = p.name.decl.ident;
|
|
177
|
-
return `${originalName}: ${typeRefElemToString(p.name.typeRef!)}`;
|
|
178
|
-
});
|
|
179
|
-
str.add(` ${name.ident.originalName}(${paramStrs.join(", ")})`);
|
|
180
|
-
listAttributeElems(attributes, str);
|
|
181
|
-
if (returnType) str.add(" -> " + typeRefElemToString(returnType));
|
|
182
|
-
}
|
|
183
|
-
|
|
184
188
|
/** show attribute names in short form to verify collection */
|
|
185
189
|
function listAttributeElems(
|
|
186
190
|
attrs: AttributeElem[] | undefined,
|
|
@@ -191,8 +195,25 @@ function listAttributeElems(
|
|
|
191
195
|
});
|
|
192
196
|
}
|
|
193
197
|
|
|
194
|
-
function
|
|
195
|
-
|
|
198
|
+
function typeRefElemToString(elem: TypeRefElem): string {
|
|
199
|
+
if (!elem) return "?type?";
|
|
200
|
+
const nameStr =
|
|
201
|
+
typeof elem.name === "string" ? elem.name : elem.name.originalName;
|
|
202
|
+
const params = elem.templateParams?.map(templateParamToString).join(", ");
|
|
203
|
+
return params ? `${nameStr}<${params}>` : nameStr;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function addFnFields(elem: FnElem, str: LineWrapper) {
|
|
207
|
+
const { name, params, returnType, attributes } = elem;
|
|
208
|
+
str.add(` ${name.ident.originalName}(${paramListToString(params)})`);
|
|
209
|
+
listAttributeElems(attributes, str);
|
|
210
|
+
if (returnType) str.add(" -> " + typeRefElemToString(returnType));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function addDoFields(elem: DoBlockElem, str: LineWrapper) {
|
|
214
|
+
const { name, params, attributes } = elem;
|
|
215
|
+
str.add(` ${name.name}(${paramListToString(params)})`);
|
|
216
|
+
listAttributeElems(attributes, str);
|
|
196
217
|
}
|
|
197
218
|
|
|
198
219
|
function addDirective(elem: DirectiveElem, str: LineWrapper) {
|
|
@@ -210,39 +231,34 @@ function addDirective(elem: DirectiveElem, str: LineWrapper) {
|
|
|
210
231
|
listAttributeElems(attributes, str);
|
|
211
232
|
}
|
|
212
233
|
|
|
213
|
-
|
|
234
|
+
function commentsToString(label: string, comments: CommentElem[]): string {
|
|
235
|
+
const texts = comments.map(c => {
|
|
236
|
+
const text = c.srcModule.src.slice(c.start, c.end);
|
|
237
|
+
return c.blankBefore ? `'${text}'(blank)` : `'${text}'`;
|
|
238
|
+
});
|
|
239
|
+
return ` ${label}[${texts.join(", ")}]`;
|
|
240
|
+
}
|
|
241
|
+
|
|
214
242
|
function unknownExpressionToString(elem: UnknownExpressionElem): string {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return astToString(e);
|
|
221
|
-
})
|
|
222
|
-
.join(" ");
|
|
243
|
+
return astToString(elem.expression);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function attributeName(attr: Attribute): string {
|
|
247
|
+
return attr.kind === "@attribute" ? "@" + attr.name : attr.kind;
|
|
223
248
|
}
|
|
224
249
|
|
|
225
250
|
function templateParamToString(p: TypeTemplateParameter): string {
|
|
226
251
|
if (typeof p === "string") return p;
|
|
227
252
|
if (p.kind === "type") return typeRefElemToString(p);
|
|
228
|
-
//
|
|
229
|
-
return
|
|
253
|
+
// template params render inline inside <...>, so keep expressions on one line
|
|
254
|
+
return expressionToString(p);
|
|
230
255
|
}
|
|
231
256
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
export function debugContentsToString(elem: StuffElem): string {
|
|
241
|
-
return elem.contents
|
|
242
|
-
.map(c => {
|
|
243
|
-
if (c.kind === "text") return c.srcModule.src.slice(c.start, c.end);
|
|
244
|
-
if (c.kind === "ref") return c.ident.originalName; // not using mapped decl name for debug
|
|
245
|
-
return `?${c.kind}?`;
|
|
246
|
-
})
|
|
247
|
-
.join(" ");
|
|
257
|
+
/** @return "name: type, ..." for a fn/do parameter list. */
|
|
258
|
+
function paramListToString(params: FnParamElem[]): string {
|
|
259
|
+
const paramStrs = params.map(p => {
|
|
260
|
+
const { originalName } = p.name.decl.ident;
|
|
261
|
+
return `${originalName}: ${typeRefElemToString(p.name.typeRef!)}`;
|
|
262
|
+
});
|
|
263
|
+
return paramStrs.join(", ");
|
|
248
264
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./discovery/FindUnboundIdents.ts";
|
|
|
7
7
|
export * from "./discovery/PackageNameUtils.ts";
|
|
8
8
|
export * from "./LinkedWesl.ts";
|
|
9
9
|
export * from "./Linker.ts";
|
|
10
|
+
export * from "./LinkerUtil.ts";
|
|
10
11
|
export * from "./LiveDeclarations.ts";
|
|
11
12
|
export { debug, log, srcLog, validation, withLoggerAsync } from "./Logging.ts";
|
|
12
13
|
export * from "./Mangler.ts";
|
|
@@ -20,7 +21,6 @@ export * from "./Scope.ts";
|
|
|
20
21
|
export * from "./Span.ts";
|
|
21
22
|
export * from "./SrcMap.ts";
|
|
22
23
|
export * from "./StandardTypes.ts";
|
|
23
|
-
export * from "./TransformBindingStructs.ts";
|
|
24
24
|
export * from "./Util.ts";
|
|
25
25
|
export * from "./WeslBundle.ts";
|
|
26
26
|
export * from "./WeslDevice.ts";
|