@galacean/engine-shader-compiler 2.0.0-alpha.32 → 2.0.0-alpha.33
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/{dist/bundler → bundler}/cli.js +4 -2
- package/bundler/precompile.cjs.js +324 -0
- package/bundler/precompile.js +294 -0
- package/{dist/bundler → bundler}/rollup.cjs.js +4 -2
- package/{dist/bundler → bundler}/rollup.js +4 -2
- package/dist/browser.js +425 -207
- package/dist/browser.js.map +1 -1
- package/dist/browser.min.js +1 -1
- package/dist/browser.min.js.map +1 -1
- package/dist/browser.verbose.js +416 -200
- package/dist/browser.verbose.js.map +1 -1
- package/dist/browser.verbose.min.js +1 -1
- package/dist/browser.verbose.min.js.map +1 -1
- package/dist/main.js +425 -207
- package/dist/main.js.map +1 -1
- package/dist/main.verbose.js +416 -200
- package/dist/main.verbose.js.map +1 -1
- package/dist/module.js +425 -207
- package/dist/module.js.map +1 -1
- package/dist/module.verbose.js +416 -200
- package/dist/module.verbose.js.map +1 -1
- package/package.json +14 -8
- package/types/ParserUtils.d.ts +19 -6
- package/types/Preprocessor.d.ts +11 -14
- package/types/ShaderCompilerUtils.d.ts +1 -1
- package/types/lalr/LALR1.d.ts +1 -0
- package/types/lexer/Lexer.d.ts +51 -19
- package/types/parser/AST.d.ts +24 -4
package/dist/module.js
CHANGED
|
@@ -361,6 +361,9 @@ var ShaderCompilerUtils = /*#__PURE__*/ function() {
|
|
|
361
361
|
};
|
|
362
362
|
ShaderCompilerUtils.createGSError = function createGSError(message, errorName, source, location, file) {
|
|
363
363
|
console.error(message);
|
|
364
|
+
var err = new Error(message);
|
|
365
|
+
err.name = errorName;
|
|
366
|
+
return err;
|
|
364
367
|
};
|
|
365
368
|
return ShaderCompilerUtils;
|
|
366
369
|
}();
|
|
@@ -549,36 +552,46 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
549
552
|
}).filter(Boolean);
|
|
550
553
|
};
|
|
551
554
|
/**
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (_instanceof(cur, ASTNode.PrimaryExpression) && cur.children.length === 3) {
|
|
568
|
-
|
|
555
|
+
* Walk single-child precedence-chain wrappers down to a `VariableIdentifier`,
|
|
556
|
+
* returning the leaf node (or `undefined` for any compound expression).
|
|
557
|
+
*
|
|
558
|
+
* `allowParens` chooses between two callers' needs:
|
|
559
|
+
* - `true` — descend through `( expression )` form, so `(v)` resolves to
|
|
560
|
+
* `v`. Use when the caller substitutes at the expression root
|
|
561
|
+
* (aliasing, renaming); user-written parens carry no extra meaning.
|
|
562
|
+
* - `false` — any 3-child `PrimaryExpression` aborts; `(v)` stays
|
|
563
|
+
* compound. Use when the caller treats the unwrapped node as a single
|
|
564
|
+
* token (IO-struct arg drop, alias detection); user-written parens
|
|
565
|
+
* must not collapse.
|
|
566
|
+
*/ ParserUtils.unwrapBareIdentifier = function unwrapBareIdentifier(node, options) {
|
|
567
|
+
var cur = node;
|
|
568
|
+
while(true){
|
|
569
|
+
if (_instanceof(cur, ASTNode.VariableIdentifier)) return cur;
|
|
570
|
+
if (options.allowParens && _instanceof(cur, ASTNode.PrimaryExpression) && cur.children.length === 3) {
|
|
571
|
+
var inner = cur.children[1];
|
|
572
|
+
if (!_instanceof(inner, TreeNode)) return undefined;
|
|
573
|
+
cur = inner;
|
|
569
574
|
continue;
|
|
570
575
|
}
|
|
571
|
-
// Any precedence-chain wrapper with a single child forwards through.
|
|
572
|
-
// Covers PostfixExpression / PrimaryExpression(len=1) / Assignment /
|
|
573
|
-
// Conditional / LogicalOr / … all the way down — including the verbose
|
|
574
|
-
// build's full chain and the release build's elision-flattened chain.
|
|
575
576
|
if (_instanceof(cur, ASTNode.ExpressionAstNode) && cur.children.length === 1) {
|
|
576
|
-
|
|
577
|
+
var child = cur.children[0];
|
|
578
|
+
if (!_instanceof(child, TreeNode)) return undefined;
|
|
579
|
+
cur = child;
|
|
577
580
|
continue;
|
|
578
581
|
}
|
|
579
|
-
return
|
|
582
|
+
return undefined;
|
|
580
583
|
}
|
|
581
|
-
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Lexeme variant of `unwrapBareIdentifier({ allowParens: true })` for callers
|
|
587
|
+
* that already work with strings. Returns `null` for compound expressions.
|
|
588
|
+
*/ ParserUtils.extractDirectIdentLexeme = function extractDirectIdentLexeme(expr) {
|
|
589
|
+
var ident = ParserUtils.unwrapBareIdentifier(expr, {
|
|
590
|
+
allowParens: true
|
|
591
|
+
});
|
|
592
|
+
if (!ident) return null;
|
|
593
|
+
var child = ident.children[0];
|
|
594
|
+
return _instanceof(child, BaseToken) ? child.lexeme : null;
|
|
582
595
|
};
|
|
583
596
|
ParserUtils.isTerminal = function isTerminal(sm) {
|
|
584
597
|
return sm < NoneTerminal.START;
|
|
@@ -888,7 +901,7 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
888
901
|
_inherits(Lexer, BaseLexer1);
|
|
889
902
|
function Lexer(source, macroDefineList) {
|
|
890
903
|
var _this;
|
|
891
|
-
_this = BaseLexer1.call(this, source) || this, _this.macroDefineList = macroDefineList, _this._needScanMacroConditionExpression = false, _this._inMacroDefineValue = false, _this._macroDefineExpectsNameToken = false, _this._macroDefineExpectsParamsToken = false, _this.
|
|
904
|
+
_this = BaseLexer1.call(this, source) || this, _this.macroDefineList = macroDefineList, _this._needScanMacroConditionExpression = false, _this._inMacroDefineValue = false, _this._macroDefineExpectsNameToken = false, _this._macroDefineExpectsParamsToken = false, _this._currentMacroName = "", _this._currentMacroParamsLexeme = undefined, _this._currentMacroValueStart = -1, _this._branchStack = [], _this._pendingBranchPushDefined = null;
|
|
892
905
|
return _this;
|
|
893
906
|
}
|
|
894
907
|
var _proto = Lexer.prototype;
|
|
@@ -1284,11 +1297,12 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1284
1297
|
var token = BaseToken.pool.get();
|
|
1285
1298
|
var word = buffer.join("");
|
|
1286
1299
|
if (word === "#define") {
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1300
|
+
var peek = this._peekMacroDefine();
|
|
1301
|
+
if (peek && peek.isExpression) {
|
|
1302
|
+
// AST path: the value will be tokenized by the lexer's `_inMacroDefineValue`
|
|
1303
|
+
// state machine and re-parsed by the expression grammar. State machine
|
|
1304
|
+
// fills `_currentMacroName` / `_currentMacroParamsLexeme` / `_currentMacroValueStart`
|
|
1305
|
+
// as it walks the value; `_emitMacroDefineEnd` consumes them.
|
|
1292
1306
|
this._inMacroDefineValue = true;
|
|
1293
1307
|
// The next word is the macro name: force ID type even if a prior `#define`
|
|
1294
1308
|
// has already registered the name into `macroDefineList` (redefinition or
|
|
@@ -1296,10 +1310,13 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1296
1310
|
this._macroDefineExpectsNameToken = true;
|
|
1297
1311
|
token.set(Keyword.MACRO_DEFINE, "#define", start);
|
|
1298
1312
|
} else {
|
|
1313
|
+
// Legacy path: opaque token sequence. Register directly from the peek
|
|
1314
|
+
// result without re-walking the directive.
|
|
1299
1315
|
this._scanUtilBreakLine(buffer);
|
|
1300
1316
|
var lexeme = "\n" + buffer.join("") + "\n";
|
|
1301
|
-
|
|
1302
|
-
|
|
1317
|
+
if (peek) {
|
|
1318
|
+
this._registerMacroDefine(peek.name, peek.paramsLexeme, peek.valueStart, peek.valueEnd);
|
|
1319
|
+
}
|
|
1303
1320
|
token.set(Keyword.MACRO_DEFINE_EXPRESSION, lexeme, start);
|
|
1304
1321
|
}
|
|
1305
1322
|
} else {
|
|
@@ -1316,66 +1333,151 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1316
1333
|
return c === "\n" || c === "\r";
|
|
1317
1334
|
};
|
|
1318
1335
|
/**
|
|
1319
|
-
*
|
|
1320
|
-
*
|
|
1336
|
+
* Walk a `#define` directive head once and produce everything both routing
|
|
1337
|
+
* and registration need: name range, optional params range, value range,
|
|
1338
|
+
* and whether the value parses as an `expression`.
|
|
1339
|
+
*
|
|
1340
|
+
* The replacement list is split three ways:
|
|
1321
1341
|
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
1325
|
-
* literals, type-alias keywords (`#define FxaaFloat2 vec2`), constructor
|
|
1326
|
-
* calls, qualifier fragments, `#define COMMA ,` etc. — is correctly handled
|
|
1327
|
-
* by the GLSL driver via textual substitution and needs no AST.
|
|
1342
|
+
* - **AST path** (`isExpression = true`): value parses as `expression`.
|
|
1343
|
+
* Covers identifiers, literals, parenthesized sub-expressions, operator
|
|
1344
|
+
* expressions, function calls, top-level comma lists (per C99 §6.10.3).
|
|
1328
1345
|
*
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1333
|
-
|
|
1346
|
+
* - **Legacy opaque path** (`isExpression = false`, no throw): the three
|
|
1347
|
+
* GLSL-ES-§3.4-legal-but-not-an-expression shapes with real-world use —
|
|
1348
|
+
* 1. empty value e.g. `#define COMMON_INCLUDED`
|
|
1349
|
+
* 2. single type/qualifier keyword e.g. `#define FxaaFloat float`
|
|
1350
|
+
* 3. type-qualifier list e.g. `#define TEX_PARAM(s) mediump sampler2D s`
|
|
1351
|
+
*
|
|
1352
|
+
* Note on X-macro support: the classical C X-macro pattern (a list
|
|
1353
|
+
* macro re-expanded with redefined `X(...)`) works fine — it uses
|
|
1354
|
+
* function-like macros + `\` line-continuation + `#undef`, all of
|
|
1355
|
+
* which Galacean supports. It does NOT require unbalanced parens.
|
|
1356
|
+
*
|
|
1357
|
+
* - **Authoring error** (throws): every other shape that's not a valid
|
|
1358
|
+
* `expression`. Legal token sequences in theory but not used in real
|
|
1359
|
+
* GLSL — almost always author mistakes. We surface one uniform
|
|
1360
|
+
* diagnostic with the macro name and value text and let the user fix
|
|
1361
|
+
* their code instead of routing politely.
|
|
1362
|
+
*
|
|
1363
|
+
* Unsupported shapes that throw (non-exhaustive — the predicate is
|
|
1364
|
+
* "the value doesn't reduce as `expression` and isn't one of the three
|
|
1365
|
+
* legacy shapes above"):
|
|
1366
|
+
* - leading bare punctuation `,` `;` `:` `?` `)` `]`
|
|
1367
|
+
* - trailing `,` or `;` e.g. `#define X a, b,`
|
|
1368
|
+
* - trailing binary / unary op `+` `-` `*` `/` `%` `&` `|` `^`
|
|
1369
|
+
* `<` `>` `=` `!` `~`
|
|
1370
|
+
* - trailing ternary fragment `?` or `:`
|
|
1371
|
+
* - unbalanced `[` / `]` e.g. `#define X a[b`
|
|
1372
|
+
* - unbalanced `(` / `)` e.g. `#define PAREN (`
|
|
1373
|
+
*
|
|
1374
|
+
* Returns `null` if the directive is malformed before the name. `cursor` is
|
|
1375
|
+
* the position past the last non-newline char (caller advances from there).
|
|
1376
|
+
*/ _proto._peekMacroDefine = function _peekMacroDefine() {
|
|
1334
1377
|
var src = this._source;
|
|
1335
1378
|
var len = src.length;
|
|
1336
|
-
// All position advancement goes through `_skipNonSemantic`, which honors
|
|
1337
|
-
// line-continuation (`\` + newline) and skips comments. This is critical:
|
|
1338
|
-
// `#define UV foo \\\n .field` is one logical directive whose value
|
|
1339
|
-
// contains `.field`, and `#define HP /* a.b */ highp` must not let the
|
|
1340
|
-
// `.` inside the comment trigger AST routing.
|
|
1341
1379
|
var i = Lexer._skipNonSemantic(src, this._currentIndex, len);
|
|
1342
|
-
|
|
1343
|
-
|
|
1380
|
+
if (!(i < len && BaseLexer.isAlpha(src.charCodeAt(i)))) return null;
|
|
1381
|
+
var nameStart = i;
|
|
1344
1382
|
while(i < len && BaseLexer.isAlnum(src.charCodeAt(i)))i++;
|
|
1345
|
-
|
|
1346
|
-
// Optional `(params)
|
|
1347
|
-
|
|
1383
|
+
var name = src.slice(nameStart, i);
|
|
1384
|
+
// Optional `(params)` glued to the name (function-like per C99 §6.10.3/10;
|
|
1385
|
+
// whitespace before `(` makes it object-like — `(` becomes part of value).
|
|
1386
|
+
var paramsLexeme;
|
|
1387
|
+
if (i < len && src.charCodeAt(i) === 40 /* '(' */ ) {
|
|
1388
|
+
var paramsStart = i;
|
|
1348
1389
|
var depth = 1;
|
|
1349
1390
|
i++;
|
|
1350
1391
|
while(i < len && depth > 0){
|
|
1351
1392
|
i = Lexer._skipNonSemantic(src, i, len);
|
|
1393
|
+
if (i >= len) break;
|
|
1352
1394
|
var c = src.charCodeAt(i);
|
|
1353
|
-
if (c === 10 || c === 13)
|
|
1395
|
+
if (c === 10 || c === 13) {
|
|
1396
|
+
// Unbalanced before newline — treat as malformed function-like.
|
|
1397
|
+
return {
|
|
1398
|
+
name: name,
|
|
1399
|
+
paramsLexeme: undefined,
|
|
1400
|
+
valueStart: i,
|
|
1401
|
+
valueEnd: i,
|
|
1402
|
+
cursor: i,
|
|
1403
|
+
isExpression: false
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1354
1406
|
if (c === 40) depth++;
|
|
1355
1407
|
else if (c === 41 /* ')' */ ) depth--;
|
|
1356
1408
|
i++;
|
|
1357
1409
|
}
|
|
1410
|
+
paramsLexeme = src.slice(paramsStart, i);
|
|
1358
1411
|
}
|
|
1359
|
-
//
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1412
|
+
// Walk the value once tracking what routing needs.
|
|
1413
|
+
var valueStart = i;
|
|
1414
|
+
var parenDepth = 0;
|
|
1415
|
+
var bracketDepth = 0;
|
|
1416
|
+
var firstStart = -1;
|
|
1417
|
+
var firstEnd = -1;
|
|
1418
|
+
var firstFollowedByParen = false;
|
|
1419
|
+
var topLevelLast = -1;
|
|
1364
1420
|
while(i < len){
|
|
1365
|
-
|
|
1366
|
-
if (
|
|
1421
|
+
var skipped = Lexer._skipNonSemantic(src, i, len);
|
|
1422
|
+
if (skipped !== i) {
|
|
1423
|
+
i = skipped;
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1367
1426
|
var c1 = src.charCodeAt(i);
|
|
1368
|
-
if (c1 === 10 || c1 === 13) break;
|
|
1369
|
-
if (
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1427
|
+
if (c1 === 10 || c1 === 13) break;
|
|
1428
|
+
if (firstStart === -1) {
|
|
1429
|
+
firstStart = i;
|
|
1430
|
+
if (BaseLexer.isAlpha(c1)) {
|
|
1431
|
+
while(i < len && BaseLexer.isAlnum(src.charCodeAt(i)))i++;
|
|
1432
|
+
firstEnd = i;
|
|
1433
|
+
var after = Lexer._skipNonSemantic(src, i, len);
|
|
1434
|
+
firstFollowedByParen = after < len && src.charCodeAt(after) === 40;
|
|
1435
|
+
topLevelLast = firstEnd - 1;
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1375
1438
|
}
|
|
1439
|
+
if (c1 === 40) parenDepth++;
|
|
1440
|
+
else if (c1 === 41) parenDepth--;
|
|
1441
|
+
else if (c1 === 91 /* [ */ ) bracketDepth++;
|
|
1442
|
+
else if (c1 === 93 /* ] */ ) bracketDepth--;
|
|
1443
|
+
if (parenDepth === 0 && bracketDepth === 0) topLevelLast = i;
|
|
1376
1444
|
i++;
|
|
1377
1445
|
}
|
|
1378
|
-
|
|
1446
|
+
var result = {
|
|
1447
|
+
name: name,
|
|
1448
|
+
paramsLexeme: paramsLexeme,
|
|
1449
|
+
valueStart: valueStart,
|
|
1450
|
+
valueEnd: i,
|
|
1451
|
+
cursor: i,
|
|
1452
|
+
isExpression: false
|
|
1453
|
+
};
|
|
1454
|
+
// Real-world legacy shapes:
|
|
1455
|
+
// 1. empty value, 2. single type/qualifier kw, 3. type-qualifier list.
|
|
1456
|
+
if (firstStart === -1) return result;
|
|
1457
|
+
if (firstEnd !== -1 && !firstFollowedByParen && Lexer._isNonExpressionLeadingKeyword(src.slice(firstStart, firstEnd))) {
|
|
1458
|
+
return result;
|
|
1459
|
+
}
|
|
1460
|
+
// Authoring errors. Anything that's neither a legal `expression` nor one
|
|
1461
|
+
// of the three legacy shapes above gets a single uniform diagnostic —
|
|
1462
|
+
// the user sees the macro name and the value text, that's enough to
|
|
1463
|
+
// locate and fix. We don't categorize further; the rule for users is
|
|
1464
|
+
// simply "value must be a valid GLSL expression".
|
|
1465
|
+
//
|
|
1466
|
+
// Legal expression starts: alnum (identifier / literal), `(` (group),
|
|
1467
|
+
// `.` (GLSL ES §4.1.4 leading-dot float literal like `.5`), `-`/`+`/`!`/`~`
|
|
1468
|
+
// (unary). Legal expression ends: alnum (identifier / literal), `)` (group
|
|
1469
|
+
// close), `]` (array-index close). Everything else at the head or
|
|
1470
|
+
// top-level tail is an authoring error.
|
|
1471
|
+
var head = src.charCodeAt(firstStart);
|
|
1472
|
+
var tail = topLevelLast >= 0 ? src.charCodeAt(topLevelLast) : 0;
|
|
1473
|
+
var headIllegal = !BaseLexer.isAlnum(head) && head !== 40 /* ( */ && head !== 46 /* . */ && head !== 45 /* - */ && head !== 43 /* + */ && head !== 33 /* ! */ && head !== 126; /* ~ */
|
|
1474
|
+
var tailIllegal = !BaseLexer.isAlnum(tail) && tail !== 41 /* ) */ && tail !== 93; /* ] */
|
|
1475
|
+
if (parenDepth !== 0 || bracketDepth !== 0 || headIllegal || tailIllegal) {
|
|
1476
|
+
var valueText = src.slice(firstStart, i).replace(/\s+/g, " ").trim();
|
|
1477
|
+
this.throwError(this.getShaderPosition(0), "#define " + name + ': invalid replacement list — not a valid GLSL expression ("' + valueText + '")');
|
|
1478
|
+
}
|
|
1479
|
+
result.isExpression = true;
|
|
1480
|
+
return result;
|
|
1379
1481
|
};
|
|
1380
1482
|
/** Consuming wrapper around `_skipNonSemantic` operating on the lexer's
|
|
1381
1483
|
* current position. Used by the `#define`-value scan state machine. Goes
|
|
@@ -1419,11 +1521,16 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1419
1521
|
this.advance(1);
|
|
1420
1522
|
}
|
|
1421
1523
|
var token = BaseToken.pool.get();
|
|
1422
|
-
|
|
1524
|
+
var lexeme = buffer.join("");
|
|
1525
|
+
this._currentMacroParamsLexeme = lexeme;
|
|
1526
|
+
// Value starts after the `)` we just consumed.
|
|
1527
|
+
this._currentMacroValueStart = this._currentIndex;
|
|
1528
|
+
token.set(Keyword.MACRO_DEFINE_PARAMS, lexeme, start);
|
|
1423
1529
|
return token;
|
|
1424
1530
|
};
|
|
1425
1531
|
/** Emit `MACRO_DEFINE_END` at the end of a `#define` value, consuming the newline. */ _proto._emitMacroDefineEnd = function _emitMacroDefineEnd() {
|
|
1426
1532
|
var start = this.getShaderPosition();
|
|
1533
|
+
var valueEnd = this._currentIndex;
|
|
1427
1534
|
var source = this._source;
|
|
1428
1535
|
if (this._currentIndex < source.length) {
|
|
1429
1536
|
var c = source.charCodeAt(this._currentIndex);
|
|
@@ -1433,37 +1540,29 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1433
1540
|
this.advance(1);
|
|
1434
1541
|
}
|
|
1435
1542
|
}
|
|
1436
|
-
|
|
1437
|
-
this._registerMacroDefine(this._source.slice(this._macroDefineDirectiveStart, this._currentIndex));
|
|
1543
|
+
this._registerMacroDefine(this._currentMacroName, this._currentMacroParamsLexeme, this._currentMacroValueStart, valueEnd);
|
|
1438
1544
|
this._inMacroDefineValue = false;
|
|
1439
1545
|
var token = BaseToken.pool.get();
|
|
1440
1546
|
token.set(Keyword.MACRO_DEFINE_END, "\n", start);
|
|
1441
1547
|
return token;
|
|
1442
1548
|
};
|
|
1443
|
-
//
|
|
1444
|
-
//
|
|
1445
|
-
//
|
|
1446
|
-
_proto._registerMacroDefine = function _registerMacroDefine(
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
// the next physical line onto this one. The regex's value group rejects
|
|
1450
|
-
// newlines, so without folding any multi-line directive (`#define X a \\\n + b`)
|
|
1451
|
-
// would NO MATCH and registration would silently fail.
|
|
1452
|
-
var folded = directive.replace(Lexer._lineContinuationReg, "");
|
|
1453
|
-
var m = Lexer._defineDirectiveReg.exec(folded);
|
|
1454
|
-
if (!m) return;
|
|
1455
|
-
var name = m[1];
|
|
1456
|
-
var paramsStr = m[3];
|
|
1457
|
-
var valueRaw = m[4];
|
|
1458
|
-
var params = paramsStr ? paramsStr.split(",").map(function(p) {
|
|
1549
|
+
// Register a `#define` directive. Both AST and legacy paths funnel through
|
|
1550
|
+
// here using ranges already extracted by `_peekMacroDefine` / the value
|
|
1551
|
+
// state machine — no re-parsing the directive text.
|
|
1552
|
+
_proto._registerMacroDefine = function _registerMacroDefine(name, paramsLexeme, valueStart, valueEnd) {
|
|
1553
|
+
var params = paramsLexeme ? paramsLexeme.slice(1, -1) // strip enclosing `(` `)`
|
|
1554
|
+
.split(",").map(function(p) {
|
|
1459
1555
|
return p.trim();
|
|
1460
1556
|
}).filter(Boolean) : [];
|
|
1461
|
-
|
|
1557
|
+
// Dedup key: normalized value text (same lexical view the token-stream
|
|
1558
|
+
// path sees — comments stripped, whitespace collapsed). Two `#define`s
|
|
1559
|
+
// with the same name but different value text produce different keys,
|
|
1560
|
+
// so disjoint-branch entries stay separate.
|
|
1561
|
+
var dedupKey = (paramsLexeme != null ? paramsLexeme : "") + "=" + Lexer._normalizeValueText(this._source, valueStart, valueEnd);
|
|
1462
1562
|
var info = {
|
|
1463
|
-
isFunction:
|
|
1464
|
-
name: name,
|
|
1563
|
+
isFunction: paramsLexeme !== undefined,
|
|
1465
1564
|
params: params,
|
|
1466
|
-
|
|
1565
|
+
dedupKey: dedupKey,
|
|
1467
1566
|
branch: this._branchStack.length === 0 ? EMPTY_BRANCH : this._branchStack.slice()
|
|
1468
1567
|
};
|
|
1469
1568
|
var arr = this.macroDefineList[name];
|
|
@@ -1473,14 +1572,11 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1473
1572
|
];
|
|
1474
1573
|
return;
|
|
1475
1574
|
}
|
|
1476
|
-
//
|
|
1477
|
-
//
|
|
1478
|
-
// picks the visible one); same branch + same shape → drop.
|
|
1575
|
+
// Same key + same branch → duplicate (re-include). Different branches stay
|
|
1576
|
+
// separate so the visibility filter picks the right entry at each call site.
|
|
1479
1577
|
for(var i = 0, n = arr.length; i < n; i++){
|
|
1480
1578
|
var e = arr[i];
|
|
1481
|
-
if (e.
|
|
1482
|
-
return p === info.params[idx];
|
|
1483
|
-
}) && Lexer.sameBranch(e.branch, info.branch)) return;
|
|
1579
|
+
if (e.dedupKey === dedupKey && Lexer.sameBranch(e.branch, info.branch)) return;
|
|
1484
1580
|
}
|
|
1485
1581
|
arr.push(info);
|
|
1486
1582
|
};
|
|
@@ -1510,6 +1606,8 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1510
1606
|
// Bypass MACRO_CALL classification for this one word. Used for the name of
|
|
1511
1607
|
// a `#define` directive so redefining a known macro still yields a declarer ID.
|
|
1512
1608
|
this._macroDefineExpectsNameToken = false;
|
|
1609
|
+
this._currentMacroName = word;
|
|
1610
|
+
this._currentMacroParamsLexeme = undefined;
|
|
1513
1611
|
// C99 §6.10.3/3: the macro is function-like only when `(` appears *immediately*
|
|
1514
1612
|
// after the name (no intervening whitespace). `#define FOO (1+2)` is
|
|
1515
1613
|
// object-like with value `(1+2)`, not a function-like macro `FOO()` with
|
|
@@ -1517,6 +1615,10 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1517
1615
|
// on the next `scanToken`, so a space-separated `(` stays part of the value.
|
|
1518
1616
|
if (this._inMacroDefineValue) {
|
|
1519
1617
|
this._macroDefineExpectsParamsToken = this.getCurChar() === "(";
|
|
1618
|
+
// For object-like macros, the value begins where the cursor is now
|
|
1619
|
+
// (after the name, before whitespace skipping). Function-like macros
|
|
1620
|
+
// overwrite this in `_scanMacroDefineParams` after capturing `(...)`.
|
|
1621
|
+
this._currentMacroValueStart = this._currentIndex;
|
|
1520
1622
|
}
|
|
1521
1623
|
token.set(ETokenType.ID, word, start);
|
|
1522
1624
|
} else if (this._isVisibleMacro(word)) {
|
|
@@ -1656,6 +1758,12 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1656
1758
|
}
|
|
1657
1759
|
return true;
|
|
1658
1760
|
};
|
|
1761
|
+
/** GLSL type / qualifier keywords that aren't expression starters when standing alone.
|
|
1762
|
+
* `true` / `false` are excluded — they're `primary_expression` literals.
|
|
1763
|
+
* `#`-prefixed entries are excluded — they're preprocessor directive names. */ Lexer._isNonExpressionLeadingKeyword = function _isNonExpressionLeadingKeyword(lexeme) {
|
|
1764
|
+
var kw = Lexer._lexemeTable[lexeme];
|
|
1765
|
+
return kw !== undefined && kw !== Keyword.True && kw !== Keyword.False && !lexeme.startsWith("#");
|
|
1766
|
+
};
|
|
1659
1767
|
/**
|
|
1660
1768
|
* If `i` points at a `\` immediately followed by a newline (`\n`, `\r`, or
|
|
1661
1769
|
* `\r\n`), return the index just past the pair (a single atom in the C/GLSL
|
|
@@ -1663,8 +1771,7 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1663
1771
|
* source of truth for line-continuation detection — callers along the
|
|
1664
1772
|
* directive-scanning path (`_skipNonSemantic`, `_scanUtilBreakLine`,
|
|
1665
1773
|
* `_scanMacroDefineParams`) all delegate here so the rule stays in one
|
|
1666
|
-
* place.
|
|
1667
|
-
* used by `_registerMacroDefine` for one-shot folding.
|
|
1774
|
+
* place.
|
|
1668
1775
|
*/ Lexer._skipLineContinuation = function _skipLineContinuation(src, i, len) {
|
|
1669
1776
|
if (src.charCodeAt(i) !== 92 /* '\\' */ || i + 1 >= len) return i;
|
|
1670
1777
|
var n = src.charCodeAt(i + 1);
|
|
@@ -1707,6 +1814,34 @@ var GSErrorName = /*#__PURE__*/ function(GSErrorName) {
|
|
|
1707
1814
|
}
|
|
1708
1815
|
return i;
|
|
1709
1816
|
};
|
|
1817
|
+
/** Render a `[start, end)` value range as space-separated significant chars,
|
|
1818
|
+
* using the same comment / line-continuation rules `_skipNonSemantic`
|
|
1819
|
+
* applies on the token-stream path. Used as the dedup key body. */ Lexer._normalizeValueText = function _normalizeValueText(src, start, end) {
|
|
1820
|
+
var out = "";
|
|
1821
|
+
var i = start;
|
|
1822
|
+
var pendingSpace = false;
|
|
1823
|
+
while(i < end){
|
|
1824
|
+
var skipped = Lexer._skipNonSemantic(src, i, end);
|
|
1825
|
+
if (skipped !== i) {
|
|
1826
|
+
pendingSpace = out.length > 0;
|
|
1827
|
+
i = skipped;
|
|
1828
|
+
continue;
|
|
1829
|
+
}
|
|
1830
|
+
var c = src.charCodeAt(i);
|
|
1831
|
+
if (c === 32 || c === 9) {
|
|
1832
|
+
pendingSpace = out.length > 0;
|
|
1833
|
+
i++;
|
|
1834
|
+
continue;
|
|
1835
|
+
}
|
|
1836
|
+
if (pendingSpace) {
|
|
1837
|
+
out += " ";
|
|
1838
|
+
pendingSpace = false;
|
|
1839
|
+
}
|
|
1840
|
+
out += src[i];
|
|
1841
|
+
i++;
|
|
1842
|
+
}
|
|
1843
|
+
return out;
|
|
1844
|
+
};
|
|
1710
1845
|
return Lexer;
|
|
1711
1846
|
}(BaseLexer);
|
|
1712
1847
|
Lexer._lexemeTable = {
|
|
@@ -1783,12 +1918,6 @@ Lexer._lexemeTable = {
|
|
|
1783
1918
|
"#endif": Keyword.MACRO_ENDIF,
|
|
1784
1919
|
"#undef": Keyword.MACRO_UNDEF
|
|
1785
1920
|
};
|
|
1786
|
-
// Single source of truth for `#define` parsing — fed from both AST and legacy paths.
|
|
1787
|
-
Lexer._defineDirectiveReg = /^\s*#define\s+(\w+)[ ]*(\(([^)]*)\))?(?:[ \t]+([^\n\r]*?))?\s*$/;
|
|
1788
|
-
// Bare identifier or call form only — mixed-operator values reject.
|
|
1789
|
-
Lexer._referenceReg = /^([a-zA-Z_]\w*)(?:\s*\(.*\))?$/;
|
|
1790
|
-
// C preprocessor line continuation.
|
|
1791
|
-
Lexer._lineContinuationReg = /\\(?:\r\n|\n|\r)/g;
|
|
1792
1921
|
// Synthetic `__if_<n>` per `#if` — polarity flip makes `#else` mutually exclusive in `isVisibleFrom`.
|
|
1793
1922
|
Lexer._ifCounter = 0;
|
|
1794
1923
|
|
|
@@ -3991,34 +4120,13 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
3991
4120
|
var child = this.children[0];
|
|
3992
4121
|
var referenceGlobalSymbolNames = this.referenceGlobalSymbolNames;
|
|
3993
4122
|
var symbols = this._symbols;
|
|
3994
|
-
|
|
3995
|
-
var needFindNames
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
// At a MACRO_CALL use site, also probe the macro name itself so
|
|
3999
|
-
// the sibling-arm declaration is marked as referenced and codegen
|
|
4000
|
-
// keeps it. Grammar half of the fix is in 87cb2b5f0.
|
|
4001
|
-
var macroNameAsVarLookup = null;
|
|
4002
|
-
if (_instanceof(child, BaseToken)) {
|
|
4003
|
-
needFindNames = [
|
|
4004
|
-
child.lexeme
|
|
4005
|
-
];
|
|
4006
|
-
} else {
|
|
4007
|
-
var callSymbol = child;
|
|
4008
|
-
needFindNames = callSymbol.referenceSymbolNames;
|
|
4009
|
-
var macroName = callSymbol.macroName;
|
|
4010
|
-
if (macroName && needFindNames.indexOf(macroName) === -1) {
|
|
4011
|
-
needFindNames = needFindNames.concat(macroName);
|
|
4012
|
-
macroNameAsVarLookup = macroName;
|
|
4013
|
-
}
|
|
4014
|
-
}
|
|
4123
|
+
// Real references — every name must resolve; miss is an authoring error.
|
|
4124
|
+
var needFindNames = _instanceof(child, BaseToken) ? [
|
|
4125
|
+
child.lexeme
|
|
4126
|
+
] : child.referenceSymbolNames;
|
|
4015
4127
|
for(var i = 0; i < needFindNames.length; i++){
|
|
4016
4128
|
var name = needFindNames[i];
|
|
4017
|
-
|
|
4018
|
-
// so cross-arm shadowing can resolve the sibling-arm declaration.
|
|
4019
|
-
if (sa.macroDefineList[name] && name !== macroNameAsVarLookup) {
|
|
4020
|
-
continue;
|
|
4021
|
-
}
|
|
4129
|
+
if (sa.macroDefineList[name]) continue;
|
|
4022
4130
|
// only `macro_call` CFG can reference fnSymbols, others fnSymbols are referenced in `function_call_generic` CFG
|
|
4023
4131
|
if (!_instanceof(child, BaseToken) && BuiltinFunction.isExist(name)) {
|
|
4024
4132
|
continue;
|
|
@@ -4028,29 +4136,24 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4028
4136
|
this.typeInfo = builtinVar.type;
|
|
4029
4137
|
continue;
|
|
4030
4138
|
}
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
var _symbols__dataType;
|
|
4040
|
-
this.typeInfo = (_symbols__dataType = symbols[0].dataType) == null ? void 0 : _symbols__dataType.type;
|
|
4041
|
-
}
|
|
4042
|
-
var currentScopeSymbol = sa.symbolTableStack.scope.getSymbol(lookupSymbol, true);
|
|
4043
|
-
if (currentScopeSymbol) {
|
|
4044
|
-
if ((_instanceof(currentScopeSymbol, FnSymbol) || currentScopeSymbol.isGlobalVariable) && referenceGlobalSymbolNames.indexOf(name) === -1) {
|
|
4045
|
-
referenceGlobalSymbolNames.push(name);
|
|
4046
|
-
}
|
|
4047
|
-
} else if (symbols.some(function(s) {
|
|
4048
|
-
return _instanceof(s, FnSymbol) || s.isGlobalVariable;
|
|
4049
|
-
}) && referenceGlobalSymbolNames.indexOf(name) === -1) {
|
|
4050
|
-
referenceGlobalSymbolNames.push(name);
|
|
4051
|
-
}
|
|
4139
|
+
var hit = VariableIdentifier._lookupAndMarkGlobalReference(sa, name, symbols, referenceGlobalSymbolNames, this.location);
|
|
4140
|
+
// Expression-style macros have their own value AST; its real type isn't
|
|
4141
|
+
// the type of any single `referenceSymbolNames` entry (`v` in `v.v_uv`
|
|
4142
|
+
// is a `Varyings` struct but the macro call site's type should be the
|
|
4143
|
+
// member type). Skip type inference for those and keep TypeAny.
|
|
4144
|
+
if (hit && (_instanceof(child, BaseToken) || !child.hasAstValue)) {
|
|
4145
|
+
var _symbols__dataType;
|
|
4146
|
+
this.typeInfo = (_symbols__dataType = symbols[0].dataType) == null ? void 0 : _symbols__dataType.type;
|
|
4052
4147
|
}
|
|
4053
4148
|
}
|
|
4149
|
+
// FXAA-style cross-arm shadowing: at a MACRO_CALL use site, silently
|
|
4150
|
+
// probe the macro name itself so any sibling-arm `var` declaration is
|
|
4151
|
+
// marked as referenced and codegen keeps it. Miss is the common
|
|
4152
|
+
// single-arm case — no warning, no type inference. Grammar half of the
|
|
4153
|
+
// cross-arm fix is in 87cb2b5f0.
|
|
4154
|
+
if (!_instanceof(child, BaseToken)) {
|
|
4155
|
+
VariableIdentifier._probeCrossArmShadowing(sa, child, needFindNames, symbols, referenceGlobalSymbolNames);
|
|
4156
|
+
}
|
|
4054
4157
|
};
|
|
4055
4158
|
_proto.codeGen = function codeGen(visitor) {
|
|
4056
4159
|
return this.setCache(visitor.visitVariableIdentifier(this));
|
|
@@ -4063,6 +4166,40 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4063
4166
|
return child.codeGen(visitor);
|
|
4064
4167
|
}
|
|
4065
4168
|
};
|
|
4169
|
+
/** Run the cross-arm shadowing probe for a MACRO_CALL site. No-op when the
|
|
4170
|
+
* probe isn't meaningful: no macro name, name already resolved as a real
|
|
4171
|
+
* reference, or name is a builtin (builtins can't be shadowed by a
|
|
4172
|
+
* sibling-arm decl). */ VariableIdentifier._probeCrossArmShadowing = function _probeCrossArmShadowing(sa, child, needFindNames, symbols, referenceGlobalSymbolNames) {
|
|
4173
|
+
var macroName = child.macroName;
|
|
4174
|
+
if (!macroName) return;
|
|
4175
|
+
if (needFindNames.indexOf(macroName) !== -1) return; // already looked up as a real reference
|
|
4176
|
+
if (BuiltinFunction.isExist(macroName) || BuiltinVariable.getVar(macroName)) return; // builtins can't be shadowed
|
|
4177
|
+
VariableIdentifier._lookupAndMarkGlobalReference(sa, macroName, symbols, referenceGlobalSymbolNames, null);
|
|
4178
|
+
};
|
|
4179
|
+
/** Look up `name` in the symbol stack and, if a global var/fn declaration
|
|
4180
|
+
* exists, push it into `referenceGlobalSymbolNames`. Returns `true` iff
|
|
4181
|
+
* the lookup hit (caller can then derive type info). When `missWarnLoc`
|
|
4182
|
+
* is non-null, a miss reports a "declared before used" warning; pass
|
|
4183
|
+
* `null` for silent probes (e.g. FXAA-style cross-arm shadowing).
|
|
4184
|
+
*
|
|
4185
|
+
* Mutation contract: `symbols` is used as scratch storage — `lookupAll`
|
|
4186
|
+
* clears and refills it. On hit, the caller may read `symbols[0]` for
|
|
4187
|
+
* type info before the next call overwrites the contents. */ VariableIdentifier._lookupAndMarkGlobalReference = function _lookupAndMarkGlobalReference(sa, name, symbols, referenceGlobalSymbolNames, missWarnLoc) {
|
|
4188
|
+
var lookupSymbol = SemanticAnalyzer._lookupSymbol;
|
|
4189
|
+
lookupSymbol.set(name, ESymbolType.Any);
|
|
4190
|
+
sa.symbolTableStack.lookupAll(lookupSymbol, true, symbols);
|
|
4191
|
+
if (!symbols.length) {
|
|
4192
|
+
return false;
|
|
4193
|
+
}
|
|
4194
|
+
var currentScopeSymbol = sa.symbolTableStack.scope.getSymbol(lookupSymbol, true);
|
|
4195
|
+
var isGlobal = currentScopeSymbol ? _instanceof(currentScopeSymbol, FnSymbol) || currentScopeSymbol.isGlobalVariable : symbols.some(function(s) {
|
|
4196
|
+
return _instanceof(s, FnSymbol) || s.isGlobalVariable;
|
|
4197
|
+
});
|
|
4198
|
+
if (isGlobal && referenceGlobalSymbolNames.indexOf(name) === -1) {
|
|
4199
|
+
referenceGlobalSymbolNames.push(name);
|
|
4200
|
+
}
|
|
4201
|
+
return true;
|
|
4202
|
+
};
|
|
4066
4203
|
return VariableIdentifier;
|
|
4067
4204
|
}(TreeNode);
|
|
4068
4205
|
ASTNode.VariableIdentifier = VariableIdentifier;
|
|
@@ -4319,18 +4456,16 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4319
4456
|
MacroBranch = __decorate([
|
|
4320
4457
|
ASTNodeDecorator(NoneTerminal.macro_branch)
|
|
4321
4458
|
], MacroBranch);
|
|
4322
|
-
var MacroCallSymbol = /*#__PURE__*/ function(
|
|
4323
|
-
_inherits(MacroCallSymbol,
|
|
4459
|
+
var MacroCallSymbol = /*#__PURE__*/ function(TreeNode1) {
|
|
4460
|
+
_inherits(MacroCallSymbol, TreeNode1);
|
|
4324
4461
|
function MacroCallSymbol() {
|
|
4325
4462
|
var _this;
|
|
4326
|
-
_this =
|
|
4463
|
+
_this = TreeNode1.apply(this, arguments) || this, _this.referenceSymbolNames = [], /** True iff every `MacroDefineInfo` visible from this call site's branch
|
|
4327
4464
|
* has a `valueAst` (i.e. was parsed via the `macro_define` CFG rule).
|
|
4328
4465
|
* Call sites use this to skip naive type inference: an AST-form macro
|
|
4329
4466
|
* drives the call site's type through its own value subtree, not through
|
|
4330
4467
|
* a root of `referenceSymbolNames`. Mixed forms across branches → false,
|
|
4331
|
-
* fall back to legacy inference. */ _this.hasAstValue = false, /**
|
|
4332
|
-
* Used by `MacroCallFunction` codegen to pick between the two call shapes
|
|
4333
|
-
* — object-like-macro-as-function-name vs true function-like macro. */ _this.isFunctionLikeMacro = false;
|
|
4468
|
+
* fall back to legacy inference. */ _this.hasAstValue = false, /** `#define NAME(params) …` form — drives function-like vs object-like codegen. */ _this.isFunctionLikeMacro = false, /** Every visible replacement is a non-builtin identifier — assume user fn alias. */ _this.aliasesNonBuiltinIdent = false;
|
|
4334
4469
|
return _this;
|
|
4335
4470
|
}
|
|
4336
4471
|
var _proto = MacroCallSymbol.prototype;
|
|
@@ -4338,6 +4473,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4338
4473
|
this.referenceSymbolNames.length = 0;
|
|
4339
4474
|
this.hasAstValue = false;
|
|
4340
4475
|
this.isFunctionLikeMacro = false;
|
|
4476
|
+
this.aliasesNonBuiltinIdent = false;
|
|
4341
4477
|
};
|
|
4342
4478
|
_proto.semanticAnalyze = function semanticAnalyze(sa) {
|
|
4343
4479
|
var nameToken = this.children[0];
|
|
@@ -4355,6 +4491,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4355
4491
|
var visibleCount = 0;
|
|
4356
4492
|
var allAst = true;
|
|
4357
4493
|
var isFn = false;
|
|
4494
|
+
var allAliasNonBuiltinIdent = true;
|
|
4358
4495
|
if (defList) {
|
|
4359
4496
|
for(var i = 0, n = defList.length; i < n; i++){
|
|
4360
4497
|
var info = defList[i];
|
|
@@ -4362,8 +4499,30 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4362
4499
|
visibleCount++;
|
|
4363
4500
|
if (info.valueAst == null) allAst = false;
|
|
4364
4501
|
if (info.isFunction) isFn = true;
|
|
4365
|
-
|
|
4366
|
-
|
|
4502
|
+
// Harvest references from the value AST. Legacy-form macros (no
|
|
4503
|
+
// `valueAst`) hold non-expression token sequences with no user
|
|
4504
|
+
// identifiers, so nothing to collect.
|
|
4505
|
+
if (info.valueAst) {
|
|
4506
|
+
MacroCallSymbol._collectIdentifierRefs(info.valueAst, info.params, refs);
|
|
4507
|
+
}
|
|
4508
|
+
// aliasesNonBuiltinIdent: macro replacement is a single non-builtin
|
|
4509
|
+
// identifier — best-effort proxy for "this macro call site aliases a
|
|
4510
|
+
// user fn", since uniform/const aliases would surface as a GLSL
|
|
4511
|
+
// compile error later anyway. Keyword replacements (`vec3`, `mat4`)
|
|
4512
|
+
// reach here with `valueAst === undefined` (opaque path), so they
|
|
4513
|
+
// automatically fail without an explicit keyword guard.
|
|
4514
|
+
if (info.isFunction || !info.valueAst) {
|
|
4515
|
+
allAliasNonBuiltinIdent = false;
|
|
4516
|
+
} else {
|
|
4517
|
+
var leadingIdent = ParserUtils.unwrapBareIdentifier(info.valueAst, {
|
|
4518
|
+
allowParens: false
|
|
4519
|
+
});
|
|
4520
|
+
var leadingChild = leadingIdent == null ? void 0 : leadingIdent.children[0];
|
|
4521
|
+
var leadingId = _instanceof(leadingChild, BaseToken) ? leadingChild.lexeme : undefined;
|
|
4522
|
+
if (!leadingId || BuiltinFunction.isExist(leadingId)) {
|
|
4523
|
+
allAliasNonBuiltinIdent = false;
|
|
4524
|
+
}
|
|
4525
|
+
}
|
|
4367
4526
|
}
|
|
4368
4527
|
}
|
|
4369
4528
|
// Require *every* visible entry to be AST-form before taking the AST
|
|
@@ -4372,6 +4531,25 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4372
4531
|
// instead of polluting the call site with TypeAny.
|
|
4373
4532
|
this.hasAstValue = visibleCount > 0 && allAst;
|
|
4374
4533
|
this.isFunctionLikeMacro = isFn;
|
|
4534
|
+
this.aliasesNonBuiltinIdent = visibleCount > 0 && allAliasNonBuiltinIdent;
|
|
4535
|
+
};
|
|
4536
|
+
/** Push every leaf `VariableIdentifier`'s lexeme into `out`, skipping
|
|
4537
|
+
* function-like parameter names (local to the macro, not call-site refs)
|
|
4538
|
+
* and duplicates. */ MacroCallSymbol._collectIdentifierRefs = function _collectIdentifierRefs(node, params, out) {
|
|
4539
|
+
if (_instanceof(node, VariableIdentifier)) {
|
|
4540
|
+
var child = node.children[0];
|
|
4541
|
+
if (_instanceof(child, BaseToken)) {
|
|
4542
|
+
var name = child.lexeme;
|
|
4543
|
+
if (params.indexOf(name) === -1 && out.indexOf(name) === -1) out.push(name);
|
|
4544
|
+
}
|
|
4545
|
+
return;
|
|
4546
|
+
}
|
|
4547
|
+
var children = node.children;
|
|
4548
|
+
if (!children) return;
|
|
4549
|
+
for(var i = 0, n = children.length; i < n; i++){
|
|
4550
|
+
var c = children[i];
|
|
4551
|
+
if (_instanceof(c, TreeNode)) MacroCallSymbol._collectIdentifierRefs(c, params, out);
|
|
4552
|
+
}
|
|
4375
4553
|
};
|
|
4376
4554
|
return MacroCallSymbol;
|
|
4377
4555
|
}(TreeNode);
|
|
@@ -4383,7 +4561,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4383
4561
|
_inherits(MacroCallFunction, TreeNode);
|
|
4384
4562
|
function MacroCallFunction() {
|
|
4385
4563
|
var _this;
|
|
4386
|
-
_this = TreeNode.apply(this, arguments) || this, _this.referenceSymbolNames = [], _this.macroName = "", _this.hasAstValue = false, _this.isFunctionLikeMacro = false;
|
|
4564
|
+
_this = TreeNode.apply(this, arguments) || this, _this.referenceSymbolNames = [], _this.macroName = "", _this.hasAstValue = false, _this.isFunctionLikeMacro = false, _this.aliasesNonBuiltinIdent = false;
|
|
4387
4565
|
return _this;
|
|
4388
4566
|
}
|
|
4389
4567
|
var _proto = MacroCallFunction.prototype;
|
|
@@ -4392,6 +4570,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4392
4570
|
this.macroName = "";
|
|
4393
4571
|
this.hasAstValue = false;
|
|
4394
4572
|
this.isFunctionLikeMacro = false;
|
|
4573
|
+
this.aliasesNonBuiltinIdent = false;
|
|
4395
4574
|
};
|
|
4396
4575
|
_proto.semanticAnalyze = function semanticAnalyze(sa) {
|
|
4397
4576
|
var child = this.children[0];
|
|
@@ -4399,6 +4578,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4399
4578
|
this.macroName = child.macroName;
|
|
4400
4579
|
this.hasAstValue = child.hasAstValue;
|
|
4401
4580
|
this.isFunctionLikeMacro = child.isFunctionLikeMacro;
|
|
4581
|
+
this.aliasesNonBuiltinIdent = child.aliasesNonBuiltinIdent;
|
|
4402
4582
|
};
|
|
4403
4583
|
_proto.codeGen = function codeGen(visitor) {
|
|
4404
4584
|
return this.setCache(visitor.visitMacroCallFunction(this));
|
|
@@ -4434,7 +4614,10 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4434
4614
|
params = ParserUtils.parseMacroParamList(children[2].lexeme);
|
|
4435
4615
|
valueIdx = 3;
|
|
4436
4616
|
}
|
|
4437
|
-
|
|
4617
|
+
// Grammar's macro_define value is `expression` (not `assignment_expression`),
|
|
4618
|
+
// so the value child is always an `Expression` wrapper — even for a single
|
|
4619
|
+
// assignment-expression value, which appears as `Expression > AssignmentExpression`.
|
|
4620
|
+
if (_instanceof(children[valueIdx], Expression)) {
|
|
4438
4621
|
this.valueExpression = children[valueIdx];
|
|
4439
4622
|
}
|
|
4440
4623
|
// The Lexer already registered a regex-derived entry for this directive.
|
|
@@ -4457,14 +4640,14 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4457
4640
|
if (upgradable) {
|
|
4458
4641
|
upgradable.valueAst = this.valueExpression;
|
|
4459
4642
|
} else {
|
|
4460
|
-
// No matching preprocessor entry (
|
|
4461
|
-
//
|
|
4643
|
+
// No matching preprocessor entry (lexer fed directly, no
|
|
4644
|
+
// `Preprocessor.parse` pass). Synthetic key based on shape is enough
|
|
4645
|
+
// — this path's only dedup unit is this AST-direct registration.
|
|
4462
4646
|
var info = {
|
|
4463
4647
|
isFunction: this.isFunction,
|
|
4464
|
-
name: this.macroName,
|
|
4465
4648
|
params: params,
|
|
4466
4649
|
valueAst: this.valueExpression,
|
|
4467
|
-
|
|
4650
|
+
dedupKey: this.macroName + "#ast/" + (this.isFunction ? params.join(",") : ""),
|
|
4468
4651
|
branch: definingBranch
|
|
4469
4652
|
};
|
|
4470
4653
|
if (entries) entries.push(info);
|
|
@@ -4472,6 +4655,13 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4472
4655
|
info
|
|
4473
4656
|
];
|
|
4474
4657
|
}
|
|
4658
|
+
// Close the form-param scope pushed at `MACRO_DEFINE_PARAMS` shift. By
|
|
4659
|
+
// the time this reduce fires, every `VariableIdentifier` inside the
|
|
4660
|
+
// value expression has already resolved against the params. Object-like
|
|
4661
|
+
// macros never pushed a scope, so nothing to pop.
|
|
4662
|
+
if (this.isFunction) {
|
|
4663
|
+
sa.popScope();
|
|
4664
|
+
}
|
|
4475
4665
|
};
|
|
4476
4666
|
_proto.codeGen = function codeGen(visitor) {
|
|
4477
4667
|
return this.setCache(visitor.visitMacroDefine(this));
|
|
@@ -4696,30 +4886,24 @@ var TempArray = /*#__PURE__*/ function() {
|
|
|
4696
4886
|
if (_instanceof(paramList, ASTNode.FunctionCallParameterList)) {
|
|
4697
4887
|
var astNodes = paramList.paramNodes;
|
|
4698
4888
|
var context = VisitorContext.context;
|
|
4699
|
-
//
|
|
4700
|
-
//
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
// `macroDefineList[name][*].isFunction` and carries the definition shape.
|
|
4714
|
-
var params = node.isFunctionLikeMacro ? astNodes : astNodes.filter(function(arg) {
|
|
4715
|
-
if (_instanceof(arg, ASTNode.AssignmentExpression)) {
|
|
4716
|
-
var variableParam = ParserUtils.unwrapNodeByType(arg, NoneTerminal.variable_identifier);
|
|
4717
|
-
if (variableParam && typeof variableParam.typeInfo === "string" && context.getStructRole(variableParam.typeInfo)) {
|
|
4718
|
-
return false;
|
|
4889
|
+
// Drop bare IO-struct args only when the macro aliases a user fn (whose
|
|
4890
|
+
// formal was flattened). All other shapes preserve args verbatim.
|
|
4891
|
+
var params;
|
|
4892
|
+
if (node.isFunctionLikeMacro || !node.aliasesNonBuiltinIdent) {
|
|
4893
|
+
params = astNodes;
|
|
4894
|
+
} else {
|
|
4895
|
+
params = astNodes.filter(function(arg) {
|
|
4896
|
+
if (_instanceof(arg, ASTNode.AssignmentExpression)) {
|
|
4897
|
+
var variableParam = ParserUtils.unwrapBareIdentifier(arg, {
|
|
4898
|
+
allowParens: false
|
|
4899
|
+
});
|
|
4900
|
+
if (variableParam && typeof variableParam.typeInfo === "string" && context.getStructRole(variableParam.typeInfo)) {
|
|
4901
|
+
return false;
|
|
4902
|
+
}
|
|
4719
4903
|
}
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
}
|
|
4904
|
+
return true;
|
|
4905
|
+
});
|
|
4906
|
+
}
|
|
4723
4907
|
var paramsCode = "";
|
|
4724
4908
|
for(var i = 0, length = params.length; i < length; i++){
|
|
4725
4909
|
var argNode = params[i];
|
|
@@ -5924,6 +6108,15 @@ var GLES300Visitor = /*#__PURE__*/ function(GLESVisitor) {
|
|
|
5924
6108
|
ShaderInstructionEncoder._DIRECTIVE_RE = /^[ \t]*#[ \t]*(if|ifdef|ifndef|elif|else|endif|define|undef)\b(.*)/;
|
|
5925
6109
|
ShaderInstructionEncoder._FUNC_MACRO_RE = /^(\w+)\(([^)]*)\)\s*(.*)/;
|
|
5926
6110
|
|
|
6111
|
+
var Production = function Production(goal, derivation) {
|
|
6112
|
+
this.goal = goal;
|
|
6113
|
+
this.derivation = derivation;
|
|
6114
|
+
this.id = Production._id++;
|
|
6115
|
+
Production.pool.set(this.id, this);
|
|
6116
|
+
};
|
|
6117
|
+
Production._id = 0;
|
|
6118
|
+
Production.pool = new Map();
|
|
6119
|
+
|
|
5927
6120
|
var StateItem = /*#__PURE__*/ function() {
|
|
5928
6121
|
function StateItem(production, position, lookahead) {
|
|
5929
6122
|
this._needReInfer = true;
|
|
@@ -6286,9 +6479,14 @@ var EAction = /*#__PURE__*/ function(EAction) {
|
|
|
6286
6479
|
/** Resolve shift-reduce/reduce-reduce conflict detect */ _proto._addAction = function _addAction(table, terminal, action) {
|
|
6287
6480
|
var exist = table.get(terminal);
|
|
6288
6481
|
if (exist && !GrammarUtils.isActionEqual(exist, action)) {
|
|
6289
|
-
//
|
|
6290
|
-
|
|
6291
|
-
|
|
6482
|
+
// Known shift-preferred conflicts (see TargetParser.y `%expect 2`).
|
|
6483
|
+
// Enforce shift regardless of the order `_inferNextState` registers
|
|
6484
|
+
// actions: when `exist` is already Shift and `action` is Reduce, keep
|
|
6485
|
+
// `exist` (early-return); the reverse order (`exist` Reduce, `action`
|
|
6486
|
+
// Shift) falls through to `table.set` below and Shift overwrites
|
|
6487
|
+
// Reduce. Order-independent by construction.
|
|
6488
|
+
if (LALR1._isKnownShiftPreferred(terminal, exist, action)) {
|
|
6489
|
+
if (exist.action === EAction.Shift && action.action === EAction.Reduce) return;
|
|
6292
6490
|
}
|
|
6293
6491
|
}
|
|
6294
6492
|
table.set(terminal, action);
|
|
@@ -6340,18 +6538,25 @@ var EAction = /*#__PURE__*/ function(EAction) {
|
|
|
6340
6538
|
this._firstSetNTStack.pop();
|
|
6341
6539
|
return firstSet;
|
|
6342
6540
|
};
|
|
6541
|
+
// Catalog of expected shift/reduce conflicts. Each entry must correspond to
|
|
6542
|
+
// one of TargetParser.y's `%expect`-ed conflicts; any new conflict not in
|
|
6543
|
+
// this list falls through to the verbose `conflict detect` warning so the
|
|
6544
|
+
// grammar/runtime drift is loud rather than silent.
|
|
6545
|
+
// - ELSE: dangling-else, bind to nearest `if`
|
|
6546
|
+
// - '(' + `type_specifier_nonarray → macro_call_symbol`: macro-as-type-alias
|
|
6547
|
+
// (#2974), prefer the expression-position `macro_call_function` over the
|
|
6548
|
+
// type-position reduce
|
|
6549
|
+
LALR1._isKnownShiftPreferred = function _isKnownShiftPreferred(terminal, exist, action) {
|
|
6550
|
+
if (terminal === Keyword.ELSE) return true;
|
|
6551
|
+
if (terminal !== ETokenType.LEFT_PAREN) return false;
|
|
6552
|
+
var reduce = exist.action === EAction.Reduce ? exist : action.action === EAction.Reduce ? action : null;
|
|
6553
|
+
if (!reduce) return false;
|
|
6554
|
+
var prod = Production.pool.get(reduce.target);
|
|
6555
|
+
return !!prod && prod.goal === NoneTerminal.type_specifier_nonarray && prod.derivation.length === 1 && prod.derivation[0] === NoneTerminal.macro_call_symbol;
|
|
6556
|
+
};
|
|
6343
6557
|
return LALR1;
|
|
6344
6558
|
}();
|
|
6345
6559
|
|
|
6346
|
-
var Production = function Production(goal, derivation) {
|
|
6347
|
-
this.goal = goal;
|
|
6348
|
-
this.derivation = derivation;
|
|
6349
|
-
this.id = Production._id++;
|
|
6350
|
-
Production.pool.set(this.id, this);
|
|
6351
|
-
};
|
|
6352
|
-
Production._id = 0;
|
|
6353
|
-
Production.pool = new Map();
|
|
6354
|
-
|
|
6355
6560
|
var Grammar = /*#__PURE__*/ function() {
|
|
6356
6561
|
function Grammar(start, productions) {
|
|
6357
6562
|
this.startSymbol = start;
|
|
@@ -6421,14 +6626,14 @@ var productionAndRules = [].concat(GrammarUtils.createProductionWithOptions(None
|
|
|
6421
6626
|
[
|
|
6422
6627
|
Keyword.MACRO_DEFINE,
|
|
6423
6628
|
ETokenType.ID,
|
|
6424
|
-
NoneTerminal.
|
|
6629
|
+
NoneTerminal.expression,
|
|
6425
6630
|
Keyword.MACRO_DEFINE_END
|
|
6426
6631
|
],
|
|
6427
6632
|
[
|
|
6428
6633
|
Keyword.MACRO_DEFINE,
|
|
6429
6634
|
ETokenType.ID,
|
|
6430
6635
|
Keyword.MACRO_DEFINE_PARAMS,
|
|
6431
|
-
NoneTerminal.
|
|
6636
|
+
NoneTerminal.expression,
|
|
6432
6637
|
Keyword.MACRO_DEFINE_END
|
|
6433
6638
|
]
|
|
6434
6639
|
], ASTNode.MacroDefine.pool), GrammarUtils.createProductionWithOptions(NoneTerminal.macro_call_symbol, [
|
|
@@ -7795,6 +8000,19 @@ var addTranslationRule = function(sa) {
|
|
|
7795
8000
|
var actionInfo = this.stateActionTable.get(token.type);
|
|
7796
8001
|
if ((actionInfo == null ? void 0 : actionInfo.action) === EAction.Shift) {
|
|
7797
8002
|
traceBackStack.push(token, actionInfo.target);
|
|
8003
|
+
// Function-like `#define` form params live in a scope wrapping the
|
|
8004
|
+
// value AST, mirroring how `function_header` opens a scope for GLSL
|
|
8005
|
+
// function parameters. Push on shift of `MACRO_DEFINE_PARAMS`; the
|
|
8006
|
+
// matching `popScope` runs when `MacroDefine.semanticAnalyze` reduces
|
|
8007
|
+
// the production (only the function-like alternative needs it, and
|
|
8008
|
+
// it knows that from its own children).
|
|
8009
|
+
if (token.type === Keyword.MACRO_DEFINE_PARAMS) {
|
|
8010
|
+
sematicAnalyzer.pushScope();
|
|
8011
|
+
for(var _iterator = _create_for_of_iterator_helper_loose(ParserUtils.parseMacroParamList(token.lexeme)), _step; !(_step = _iterator()).done;){
|
|
8012
|
+
var p = _step.value;
|
|
8013
|
+
sematicAnalyzer.symbolTableStack.insert(new SymbolInfo(p, ESymbolType.VAR));
|
|
8014
|
+
}
|
|
8015
|
+
}
|
|
7798
8016
|
nextToken = tokens.next();
|
|
7799
8017
|
} else if ((actionInfo == null ? void 0 : actionInfo.action) === EAction.Accept) {
|
|
7800
8018
|
sematicAnalyzer.acceptRule == null ? void 0 : sematicAnalyzer.acceptRule.call(sematicAnalyzer, sematicAnalyzer);
|
|
@@ -8702,7 +8920,7 @@ ShaderCompiler._shaderPositionPool = ShaderCompilerUtils.createObjectPool(Shader
|
|
|
8702
8920
|
ShaderCompiler._shaderRangePool = ShaderCompilerUtils.createObjectPool(ShaderRange);
|
|
8703
8921
|
|
|
8704
8922
|
//@ts-ignore
|
|
8705
|
-
var version = "2.0.0-alpha.
|
|
8923
|
+
var version = "2.0.0-alpha.33";
|
|
8706
8924
|
var mode = "Release";
|
|
8707
8925
|
console.log("Galacean Engine Shader Compiler Version: " + version + " | Mode: " + mode);
|
|
8708
8926
|
|