shaderkit 0.6.4 → 0.8.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.
- package/LICENSE +21 -21
- package/README.md +781 -781
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/package.json +46 -40
- package/src/ast.ts +425 -425
- package/src/constants.ts +1005 -1005
- package/src/generator.ts +128 -128
- package/src/hoister.ts +171 -0
- package/src/index.ts +7 -7
- package/src/minifier.ts +445 -159
- package/src/parser.ts +878 -802
- package/src/tokenizer.ts +105 -89
- package/src/visitor.ts +131 -131
package/src/tokenizer.ts
CHANGED
|
@@ -1,89 +1,105 @@
|
|
|
1
|
-
import { WGSL_KEYWORDS, WGSL_SYMBOLS, GLSL_KEYWORDS, GLSL_SYMBOLS } from './constants.js'
|
|
2
|
-
|
|
3
|
-
export type TokenType = 'whitespace' | 'comment' | 'symbol' | 'bool' | 'float' | 'int' | 'identifier' | 'keyword'
|
|
4
|
-
|
|
5
|
-
export interface Token<T = TokenType, V = string> {
|
|
6
|
-
type: T
|
|
7
|
-
value: V
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// Checks for WGSL-specific `fn foo(`, `var bar =`, `let baz =`, `const qux =`
|
|
11
|
-
const WGSL_REGEX = /\bfn\s+\w+\s*\(|\b(var|let|const)\s+\w+\s*[:=]/
|
|
12
|
-
|
|
13
|
-
const FLOAT_REGEX = /((\d+\.\d*|\d*\.\d+)([eEpP][-+]?\d+)?|\d+[eEpP][-+]?\d+)[fFhH]?/y
|
|
14
|
-
const INT_REGEX = /(0[xX][\w\d]+|\d+)[iIuU]?/y
|
|
15
|
-
const BOOL_REGEX = /^(true|false)$/
|
|
16
|
-
|
|
17
|
-
const ZERO = 48
|
|
18
|
-
const NINE = 57
|
|
19
|
-
const A = 65
|
|
20
|
-
const Z = 90
|
|
21
|
-
const LF = 10
|
|
22
|
-
const CR = 13
|
|
23
|
-
const TAB = 9
|
|
24
|
-
const SPACE = 32
|
|
25
|
-
const UNDERSCORE = 95
|
|
26
|
-
const DOT = 46
|
|
27
|
-
const SLASH = 47
|
|
28
|
-
const STAR = 42
|
|
29
|
-
const HASH = 35
|
|
30
|
-
const AT = 64
|
|
31
|
-
|
|
32
|
-
const isDigit = (c: number) => ZERO <= c && c <= NINE
|
|
33
|
-
const isAlpha = (c: number) => ((c &= ~32), A <= c && c <= Z)
|
|
34
|
-
const isLine = (c: number) => c === LF || c === CR
|
|
35
|
-
const isSpace = (c: number) => isLine(c) || c === TAB || c === SPACE
|
|
36
|
-
const isIdent = (c: number) => isAlpha(c) || isDigit(c) || c === UNDERSCORE
|
|
37
|
-
const isMacro = (c: number) => c === HASH || c === AT
|
|
38
|
-
|
|
39
|
-
// https://mrale.ph/blog/2016/11/23/making-less-dart-faster.html
|
|
40
|
-
function matchAsPrefix(regex: RegExp, string: string, start: number): string | undefined {
|
|
41
|
-
regex.lastIndex = start
|
|
42
|
-
return regex.exec(string)?.[0]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Tokenizes a string of GLSL or WGSL code.
|
|
47
|
-
*/
|
|
48
|
-
export function tokenize(code: string, index: number = 0): Token[] {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
1
|
+
import { WGSL_KEYWORDS, WGSL_SYMBOLS, GLSL_KEYWORDS, GLSL_SYMBOLS } from './constants.js'
|
|
2
|
+
|
|
3
|
+
export type TokenType = 'whitespace' | 'comment' | 'symbol' | 'bool' | 'float' | 'int' | 'identifier' | 'keyword'
|
|
4
|
+
|
|
5
|
+
export interface Token<T = TokenType, V = string> {
|
|
6
|
+
type: T
|
|
7
|
+
value: V
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Checks for WGSL-specific `fn foo(`, `var bar =`, `let baz =`, `const qux =`
|
|
11
|
+
const WGSL_REGEX = /\bfn\s+\w+\s*\(|\b(var|let|const)\s+\w+\s*[:=]/
|
|
12
|
+
|
|
13
|
+
const FLOAT_REGEX = /((\d+\.\d*|\d*\.\d+)([eEpP][-+]?\d+)?|\d+[eEpP][-+]?\d+)[fFhH]?/y
|
|
14
|
+
const INT_REGEX = /(0[xX][\w\d]+|\d+)[iIuU]?/y
|
|
15
|
+
const BOOL_REGEX = /^(true|false)$/
|
|
16
|
+
|
|
17
|
+
const ZERO = 48
|
|
18
|
+
const NINE = 57
|
|
19
|
+
const A = 65
|
|
20
|
+
const Z = 90
|
|
21
|
+
const LF = 10
|
|
22
|
+
const CR = 13
|
|
23
|
+
const TAB = 9
|
|
24
|
+
const SPACE = 32
|
|
25
|
+
const UNDERSCORE = 95
|
|
26
|
+
const DOT = 46
|
|
27
|
+
const SLASH = 47
|
|
28
|
+
const STAR = 42
|
|
29
|
+
const HASH = 35
|
|
30
|
+
const AT = 64
|
|
31
|
+
|
|
32
|
+
const isDigit = (c: number): boolean => ZERO <= c && c <= NINE
|
|
33
|
+
const isAlpha = (c: number): boolean => ((c &= ~32), A <= c && c <= Z)
|
|
34
|
+
const isLine = (c: number): boolean => c === LF || c === CR
|
|
35
|
+
const isSpace = (c: number): boolean => isLine(c) || c === TAB || c === SPACE
|
|
36
|
+
const isIdent = (c: number): boolean => isAlpha(c) || isDigit(c) || c === UNDERSCORE
|
|
37
|
+
const isMacro = (c: number): boolean => c === HASH || c === AT
|
|
38
|
+
|
|
39
|
+
// https://mrale.ph/blog/2016/11/23/making-less-dart-faster.html
|
|
40
|
+
function matchAsPrefix(regex: RegExp, string: string, start: number): string | undefined {
|
|
41
|
+
regex.lastIndex = start
|
|
42
|
+
return regex.exec(string)?.[0]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Tokenizes a string of GLSL or WGSL code.
|
|
47
|
+
*/
|
|
48
|
+
export function tokenize(code: string, index: number = 0): Token[] {
|
|
49
|
+
const [KEYWORDS, SYMBOLS] = WGSL_REGEX.test(code) ? [WGSL_KEYWORDS, WGSL_SYMBOLS] : [GLSL_KEYWORDS, GLSL_SYMBOLS]
|
|
50
|
+
|
|
51
|
+
const KEYWORDS_LIST = new Set(KEYWORDS)
|
|
52
|
+
const SYMBOLS_REGEX = new RegExp(
|
|
53
|
+
SYMBOLS.sort((a, b) => b.length - a.length)
|
|
54
|
+
.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
55
|
+
.join('|'),
|
|
56
|
+
'y',
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
const tokens: Token[] = []
|
|
60
|
+
|
|
61
|
+
let value: string | undefined
|
|
62
|
+
let start: number
|
|
63
|
+
let char: number
|
|
64
|
+
|
|
65
|
+
while (index < code.length) {
|
|
66
|
+
start = index
|
|
67
|
+
char = code.charCodeAt(index++)
|
|
68
|
+
|
|
69
|
+
if (isSpace(char)) {
|
|
70
|
+
while (isSpace(code.charCodeAt(index))) index++
|
|
71
|
+
value = code.slice(start, index)
|
|
72
|
+
tokens.push({ type: 'whitespace', value })
|
|
73
|
+
} else if (isDigit(char) || (char === DOT && isDigit(code.charCodeAt(index)))) {
|
|
74
|
+
if ((value = matchAsPrefix(FLOAT_REGEX, code, start))) {
|
|
75
|
+
index = FLOAT_REGEX.lastIndex
|
|
76
|
+
tokens.push({ type: 'float', value })
|
|
77
|
+
} else if ((value = matchAsPrefix(INT_REGEX, code, start))) {
|
|
78
|
+
index = INT_REGEX.lastIndex
|
|
79
|
+
tokens.push({ type: 'int', value })
|
|
80
|
+
}
|
|
81
|
+
} else if (isIdent(char)) {
|
|
82
|
+
while (isIdent(code.charCodeAt(index))) index++
|
|
83
|
+
value = code.slice(start, index)
|
|
84
|
+
if (BOOL_REGEX.test(value)) tokens.push({ type: 'bool', value })
|
|
85
|
+
else if (KEYWORDS_LIST.has(isMacro(code.charCodeAt(start - 1)) ? code[start - 1] + value : value))
|
|
86
|
+
tokens.push({ type: 'keyword', value })
|
|
87
|
+
else tokens.push({ type: 'identifier', value })
|
|
88
|
+
} else if (char === SLASH && code.charCodeAt(index) === SLASH) {
|
|
89
|
+
while (index < code.length && code.charCodeAt(index) !== LF) index++
|
|
90
|
+
value = code.slice(start, index)
|
|
91
|
+
index++ // consume LF
|
|
92
|
+
tokens.push({ type: 'comment', value })
|
|
93
|
+
} else if (char === SLASH && code.charCodeAt(index) === STAR) {
|
|
94
|
+
while (index < code.length && (code.charCodeAt(index - 2) !== STAR || code.charCodeAt(index - 1) !== SLASH))
|
|
95
|
+
index++
|
|
96
|
+
value = code.slice(start, index)
|
|
97
|
+
tokens.push({ type: 'comment', value })
|
|
98
|
+
} else if ((value = matchAsPrefix(SYMBOLS_REGEX, code, start))) {
|
|
99
|
+
index += value.length - 1
|
|
100
|
+
tokens.push({ type: 'symbol', value })
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return tokens
|
|
105
|
+
}
|
package/src/visitor.ts
CHANGED
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
import { type AST } from './ast'
|
|
2
|
-
|
|
3
|
-
export type Visitors = Partial<{
|
|
4
|
-
[K in AST['type']]:
|
|
5
|
-
| ((node: Extract<AST, { type: K }>, ancestors: AST[]) => void)
|
|
6
|
-
| {
|
|
7
|
-
enter?(node: Extract<AST, { type: K }>, ancestors: AST[]): void
|
|
8
|
-
exit?(node: Extract<AST, { type: K }>, ancestors: AST[]): void
|
|
9
|
-
}
|
|
10
|
-
}>
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Recurses through an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree), calling a visitor object on matching nodes.
|
|
14
|
-
*/
|
|
15
|
-
export function visit(node: AST, visitors: Visitors, ancestors: AST[] = []): void {
|
|
16
|
-
const parentAncestors = ancestors
|
|
17
|
-
const visitor = visitors[node.type]
|
|
18
|
-
|
|
19
|
-
// @ts-ignore
|
|
20
|
-
;(visitor?.enter ?? visitor)?.(node, parentAncestors)
|
|
21
|
-
|
|
22
|
-
ancestors = [...ancestors, node]
|
|
23
|
-
|
|
24
|
-
switch (node.type) {
|
|
25
|
-
case 'ArraySpecifier':
|
|
26
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
27
|
-
for (const dimension of node.dimensions) if (dimension) visit(dimension, visitors, ancestors)
|
|
28
|
-
break
|
|
29
|
-
case 'ExpressionStatement':
|
|
30
|
-
visit(node.expression, visitors, ancestors)
|
|
31
|
-
break
|
|
32
|
-
case 'BlockStatement':
|
|
33
|
-
for (const statement of node.body) visit(statement, visitors, ancestors)
|
|
34
|
-
break
|
|
35
|
-
case 'PreprocessorStatement':
|
|
36
|
-
if (node.value) for (const expression of node.value) visit(expression, visitors, ancestors)
|
|
37
|
-
break
|
|
38
|
-
case 'PrecisionQualifierStatement':
|
|
39
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
40
|
-
break
|
|
41
|
-
case 'InvariantQualifierStatement':
|
|
42
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
43
|
-
break
|
|
44
|
-
case 'ReturnStatement':
|
|
45
|
-
if (node.argument) visit(node.argument, visitors, ancestors)
|
|
46
|
-
break
|
|
47
|
-
case 'IfStatement':
|
|
48
|
-
visit(node.test, visitors, ancestors)
|
|
49
|
-
visit(node.consequent, visitors, ancestors)
|
|
50
|
-
if (node.alternate) visit(node.alternate, visitors, ancestors)
|
|
51
|
-
break
|
|
52
|
-
case 'SwitchStatement':
|
|
53
|
-
visit(node.discriminant, visitors, ancestors)
|
|
54
|
-
for (const kase of node.cases) visit(kase, visitors, ancestors)
|
|
55
|
-
break
|
|
56
|
-
case 'SwitchCase':
|
|
57
|
-
if (node.test) visit(node.test, visitors, ancestors)
|
|
58
|
-
for (const statement of node.consequent) visit(statement, visitors, ancestors)
|
|
59
|
-
break
|
|
60
|
-
case 'WhileStatement':
|
|
61
|
-
case 'DoWhileStatement':
|
|
62
|
-
visit(node.test, visitors, ancestors)
|
|
63
|
-
visit(node.body, visitors, ancestors)
|
|
64
|
-
break
|
|
65
|
-
case 'ForStatement':
|
|
66
|
-
if (node.init) visit(node.init, visitors, ancestors)
|
|
67
|
-
if (node.test) visit(node.test, visitors, ancestors)
|
|
68
|
-
if (node.update) visit(node.update, visitors, ancestors)
|
|
69
|
-
visit(node.body, visitors, ancestors)
|
|
70
|
-
break
|
|
71
|
-
case 'FunctionDeclaration':
|
|
72
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
73
|
-
visit(node.id, visitors, ancestors)
|
|
74
|
-
if (node.body) visit(node.body, visitors, ancestors)
|
|
75
|
-
break
|
|
76
|
-
case 'FunctionParameter':
|
|
77
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
78
|
-
if (node.id) visit(node.id, visitors, ancestors)
|
|
79
|
-
break
|
|
80
|
-
case 'VariableDeclaration':
|
|
81
|
-
for (const declaration of node.declarations) visit(declaration, visitors, ancestors)
|
|
82
|
-
break
|
|
83
|
-
case 'VariableDeclarator':
|
|
84
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
85
|
-
visit(node.id, visitors, ancestors)
|
|
86
|
-
if (node.init) visit(node.init, visitors, ancestors)
|
|
87
|
-
break
|
|
88
|
-
case 'StructuredBufferDeclaration':
|
|
89
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
90
|
-
for (const member of node.members) visit(member, visitors, ancestors)
|
|
91
|
-
if (node.id) visit(node.id, visitors, ancestors)
|
|
92
|
-
break
|
|
93
|
-
case 'StructDeclaration':
|
|
94
|
-
visit(node.id, visitors, ancestors)
|
|
95
|
-
for (const member of node.members) visit(member, visitors, ancestors)
|
|
96
|
-
break
|
|
97
|
-
case 'ArrayExpression':
|
|
98
|
-
visit(node.typeSpecifier, visitors, ancestors)
|
|
99
|
-
for (const element of node.elements) visit(element, visitors, ancestors)
|
|
100
|
-
break
|
|
101
|
-
case 'UnaryExpression':
|
|
102
|
-
case 'UpdateExpression':
|
|
103
|
-
visit(node.argument, visitors, ancestors)
|
|
104
|
-
break
|
|
105
|
-
case 'BinaryExpression':
|
|
106
|
-
case 'AssignmentExpression':
|
|
107
|
-
case 'LogicalExpression':
|
|
108
|
-
visit(node.left, visitors, ancestors)
|
|
109
|
-
visit(node.right, visitors, ancestors)
|
|
110
|
-
break
|
|
111
|
-
case 'MemberExpression':
|
|
112
|
-
visit(node.object, visitors, ancestors)
|
|
113
|
-
visit(node.property, visitors, ancestors)
|
|
114
|
-
break
|
|
115
|
-
case 'ConditionalExpression':
|
|
116
|
-
visit(node.test, visitors, ancestors)
|
|
117
|
-
visit(node.consequent, visitors, ancestors)
|
|
118
|
-
visit(node.alternate, visitors, ancestors)
|
|
119
|
-
break
|
|
120
|
-
case 'CallExpression':
|
|
121
|
-
visit(node.callee, visitors, ancestors)
|
|
122
|
-
for (const argument of node.arguments) visit(argument, visitors, ancestors)
|
|
123
|
-
break
|
|
124
|
-
case 'Program':
|
|
125
|
-
for (const statement of node.body) visit(statement, visitors, ancestors)
|
|
126
|
-
break
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// @ts-ignore
|
|
130
|
-
visitor?.exit?.(node, parentAncestors)
|
|
131
|
-
}
|
|
1
|
+
import { type AST } from './ast'
|
|
2
|
+
|
|
3
|
+
export type Visitors = Partial<{
|
|
4
|
+
[K in AST['type']]:
|
|
5
|
+
| ((node: Extract<AST, { type: K }>, ancestors: AST[]) => void)
|
|
6
|
+
| {
|
|
7
|
+
enter?(node: Extract<AST, { type: K }>, ancestors: AST[]): void
|
|
8
|
+
exit?(node: Extract<AST, { type: K }>, ancestors: AST[]): void
|
|
9
|
+
}
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Recurses through an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree), calling a visitor object on matching nodes.
|
|
14
|
+
*/
|
|
15
|
+
export function visit(node: AST, visitors: Visitors, ancestors: AST[] = []): void {
|
|
16
|
+
const parentAncestors = ancestors
|
|
17
|
+
const visitor = visitors[node.type]
|
|
18
|
+
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
;(visitor?.enter ?? visitor)?.(node, parentAncestors)
|
|
21
|
+
|
|
22
|
+
ancestors = [...ancestors, node]
|
|
23
|
+
|
|
24
|
+
switch (node.type) {
|
|
25
|
+
case 'ArraySpecifier':
|
|
26
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
27
|
+
for (const dimension of node.dimensions) if (dimension) visit(dimension, visitors, ancestors)
|
|
28
|
+
break
|
|
29
|
+
case 'ExpressionStatement':
|
|
30
|
+
visit(node.expression, visitors, ancestors)
|
|
31
|
+
break
|
|
32
|
+
case 'BlockStatement':
|
|
33
|
+
for (const statement of node.body) visit(statement, visitors, ancestors)
|
|
34
|
+
break
|
|
35
|
+
case 'PreprocessorStatement':
|
|
36
|
+
if (node.value) for (const expression of node.value) visit(expression, visitors, ancestors)
|
|
37
|
+
break
|
|
38
|
+
case 'PrecisionQualifierStatement':
|
|
39
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
40
|
+
break
|
|
41
|
+
case 'InvariantQualifierStatement':
|
|
42
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
43
|
+
break
|
|
44
|
+
case 'ReturnStatement':
|
|
45
|
+
if (node.argument) visit(node.argument, visitors, ancestors)
|
|
46
|
+
break
|
|
47
|
+
case 'IfStatement':
|
|
48
|
+
visit(node.test, visitors, ancestors)
|
|
49
|
+
visit(node.consequent, visitors, ancestors)
|
|
50
|
+
if (node.alternate) visit(node.alternate, visitors, ancestors)
|
|
51
|
+
break
|
|
52
|
+
case 'SwitchStatement':
|
|
53
|
+
visit(node.discriminant, visitors, ancestors)
|
|
54
|
+
for (const kase of node.cases) visit(kase, visitors, ancestors)
|
|
55
|
+
break
|
|
56
|
+
case 'SwitchCase':
|
|
57
|
+
if (node.test) visit(node.test, visitors, ancestors)
|
|
58
|
+
for (const statement of node.consequent) visit(statement, visitors, ancestors)
|
|
59
|
+
break
|
|
60
|
+
case 'WhileStatement':
|
|
61
|
+
case 'DoWhileStatement':
|
|
62
|
+
visit(node.test, visitors, ancestors)
|
|
63
|
+
visit(node.body, visitors, ancestors)
|
|
64
|
+
break
|
|
65
|
+
case 'ForStatement':
|
|
66
|
+
if (node.init) visit(node.init, visitors, ancestors)
|
|
67
|
+
if (node.test) visit(node.test, visitors, ancestors)
|
|
68
|
+
if (node.update) visit(node.update, visitors, ancestors)
|
|
69
|
+
visit(node.body, visitors, ancestors)
|
|
70
|
+
break
|
|
71
|
+
case 'FunctionDeclaration':
|
|
72
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
73
|
+
visit(node.id, visitors, ancestors)
|
|
74
|
+
if (node.body) visit(node.body, visitors, ancestors)
|
|
75
|
+
break
|
|
76
|
+
case 'FunctionParameter':
|
|
77
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
78
|
+
if (node.id) visit(node.id, visitors, ancestors)
|
|
79
|
+
break
|
|
80
|
+
case 'VariableDeclaration':
|
|
81
|
+
for (const declaration of node.declarations) visit(declaration, visitors, ancestors)
|
|
82
|
+
break
|
|
83
|
+
case 'VariableDeclarator':
|
|
84
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
85
|
+
visit(node.id, visitors, ancestors)
|
|
86
|
+
if (node.init) visit(node.init, visitors, ancestors)
|
|
87
|
+
break
|
|
88
|
+
case 'StructuredBufferDeclaration':
|
|
89
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
90
|
+
for (const member of node.members) visit(member, visitors, ancestors)
|
|
91
|
+
if (node.id) visit(node.id, visitors, ancestors)
|
|
92
|
+
break
|
|
93
|
+
case 'StructDeclaration':
|
|
94
|
+
visit(node.id, visitors, ancestors)
|
|
95
|
+
for (const member of node.members) visit(member, visitors, ancestors)
|
|
96
|
+
break
|
|
97
|
+
case 'ArrayExpression':
|
|
98
|
+
visit(node.typeSpecifier, visitors, ancestors)
|
|
99
|
+
for (const element of node.elements) visit(element, visitors, ancestors)
|
|
100
|
+
break
|
|
101
|
+
case 'UnaryExpression':
|
|
102
|
+
case 'UpdateExpression':
|
|
103
|
+
visit(node.argument, visitors, ancestors)
|
|
104
|
+
break
|
|
105
|
+
case 'BinaryExpression':
|
|
106
|
+
case 'AssignmentExpression':
|
|
107
|
+
case 'LogicalExpression':
|
|
108
|
+
visit(node.left, visitors, ancestors)
|
|
109
|
+
visit(node.right, visitors, ancestors)
|
|
110
|
+
break
|
|
111
|
+
case 'MemberExpression':
|
|
112
|
+
visit(node.object, visitors, ancestors)
|
|
113
|
+
visit(node.property, visitors, ancestors)
|
|
114
|
+
break
|
|
115
|
+
case 'ConditionalExpression':
|
|
116
|
+
visit(node.test, visitors, ancestors)
|
|
117
|
+
visit(node.consequent, visitors, ancestors)
|
|
118
|
+
visit(node.alternate, visitors, ancestors)
|
|
119
|
+
break
|
|
120
|
+
case 'CallExpression':
|
|
121
|
+
visit(node.callee, visitors, ancestors)
|
|
122
|
+
for (const argument of node.arguments) visit(argument, visitors, ancestors)
|
|
123
|
+
break
|
|
124
|
+
case 'Program':
|
|
125
|
+
for (const statement of node.body) visit(statement, visitors, ancestors)
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// @ts-ignore
|
|
130
|
+
visitor?.exit?.(node, parentAncestors)
|
|
131
|
+
}
|