@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.verbose.js
CHANGED
|
@@ -922,36 +922,46 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
922
922
|
}).filter(Boolean);
|
|
923
923
|
};
|
|
924
924
|
/**
|
|
925
|
-
*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
if (_instanceof(cur, ASTNode.PrimaryExpression) && cur.children.length === 3) {
|
|
941
|
-
|
|
925
|
+
* Walk single-child precedence-chain wrappers down to a `VariableIdentifier`,
|
|
926
|
+
* returning the leaf node (or `undefined` for any compound expression).
|
|
927
|
+
*
|
|
928
|
+
* `allowParens` chooses between two callers' needs:
|
|
929
|
+
* - `true` — descend through `( expression )` form, so `(v)` resolves to
|
|
930
|
+
* `v`. Use when the caller substitutes at the expression root
|
|
931
|
+
* (aliasing, renaming); user-written parens carry no extra meaning.
|
|
932
|
+
* - `false` — any 3-child `PrimaryExpression` aborts; `(v)` stays
|
|
933
|
+
* compound. Use when the caller treats the unwrapped node as a single
|
|
934
|
+
* token (IO-struct arg drop, alias detection); user-written parens
|
|
935
|
+
* must not collapse.
|
|
936
|
+
*/ ParserUtils.unwrapBareIdentifier = function unwrapBareIdentifier(node, options) {
|
|
937
|
+
var cur = node;
|
|
938
|
+
while(true){
|
|
939
|
+
if (_instanceof(cur, ASTNode.VariableIdentifier)) return cur;
|
|
940
|
+
if (options.allowParens && _instanceof(cur, ASTNode.PrimaryExpression) && cur.children.length === 3) {
|
|
941
|
+
var inner = cur.children[1];
|
|
942
|
+
if (!_instanceof(inner, TreeNode)) return undefined;
|
|
943
|
+
cur = inner;
|
|
942
944
|
continue;
|
|
943
945
|
}
|
|
944
|
-
// Any precedence-chain wrapper with a single child forwards through.
|
|
945
|
-
// Covers PostfixExpression / PrimaryExpression(len=1) / Assignment /
|
|
946
|
-
// Conditional / LogicalOr / … all the way down — including the verbose
|
|
947
|
-
// build's full chain and the release build's elision-flattened chain.
|
|
948
946
|
if (_instanceof(cur, ASTNode.ExpressionAstNode) && cur.children.length === 1) {
|
|
949
|
-
|
|
947
|
+
var child = cur.children[0];
|
|
948
|
+
if (!_instanceof(child, TreeNode)) return undefined;
|
|
949
|
+
cur = child;
|
|
950
950
|
continue;
|
|
951
951
|
}
|
|
952
|
-
return
|
|
952
|
+
return undefined;
|
|
953
953
|
}
|
|
954
|
-
|
|
954
|
+
};
|
|
955
|
+
/**
|
|
956
|
+
* Lexeme variant of `unwrapBareIdentifier({ allowParens: true })` for callers
|
|
957
|
+
* that already work with strings. Returns `null` for compound expressions.
|
|
958
|
+
*/ ParserUtils.extractDirectIdentLexeme = function extractDirectIdentLexeme(expr) {
|
|
959
|
+
var ident = ParserUtils.unwrapBareIdentifier(expr, {
|
|
960
|
+
allowParens: true
|
|
961
|
+
});
|
|
962
|
+
if (!ident) return null;
|
|
963
|
+
var child = ident.children[0];
|
|
964
|
+
return _instanceof(child, BaseToken) ? child.lexeme : null;
|
|
955
965
|
};
|
|
956
966
|
/**
|
|
957
967
|
* Check if type `tb` is compatible with type `ta`.
|
|
@@ -1224,7 +1234,7 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1224
1234
|
_inherits(Lexer, BaseLexer1);
|
|
1225
1235
|
function Lexer(source, macroDefineList) {
|
|
1226
1236
|
var _this;
|
|
1227
|
-
_this = BaseLexer1.call(this, source) || this, _this.macroDefineList = macroDefineList, _this._needScanMacroConditionExpression = false, _this._inMacroDefineValue = false, _this._macroDefineExpectsNameToken = false, _this._macroDefineExpectsParamsToken = false, _this.
|
|
1237
|
+
_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;
|
|
1228
1238
|
return _this;
|
|
1229
1239
|
}
|
|
1230
1240
|
var _proto = Lexer.prototype;
|
|
@@ -1620,11 +1630,12 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1620
1630
|
var token = BaseToken.pool.get();
|
|
1621
1631
|
var word = buffer.join("");
|
|
1622
1632
|
if (word === "#define") {
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1633
|
+
var peek = this._peekMacroDefine();
|
|
1634
|
+
if (peek && peek.isExpression) {
|
|
1635
|
+
// AST path: the value will be tokenized by the lexer's `_inMacroDefineValue`
|
|
1636
|
+
// state machine and re-parsed by the expression grammar. State machine
|
|
1637
|
+
// fills `_currentMacroName` / `_currentMacroParamsLexeme` / `_currentMacroValueStart`
|
|
1638
|
+
// as it walks the value; `_emitMacroDefineEnd` consumes them.
|
|
1628
1639
|
this._inMacroDefineValue = true;
|
|
1629
1640
|
// The next word is the macro name: force ID type even if a prior `#define`
|
|
1630
1641
|
// has already registered the name into `macroDefineList` (redefinition or
|
|
@@ -1632,10 +1643,13 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1632
1643
|
this._macroDefineExpectsNameToken = true;
|
|
1633
1644
|
token.set(Keyword.MACRO_DEFINE, "#define", start);
|
|
1634
1645
|
} else {
|
|
1646
|
+
// Legacy path: opaque token sequence. Register directly from the peek
|
|
1647
|
+
// result without re-walking the directive.
|
|
1635
1648
|
this._scanUtilBreakLine(buffer);
|
|
1636
1649
|
var lexeme = "\n" + buffer.join("") + "\n";
|
|
1637
|
-
|
|
1638
|
-
|
|
1650
|
+
if (peek) {
|
|
1651
|
+
this._registerMacroDefine(peek.name, peek.paramsLexeme, peek.valueStart, peek.valueEnd);
|
|
1652
|
+
}
|
|
1639
1653
|
token.set(Keyword.MACRO_DEFINE_EXPRESSION, lexeme, start);
|
|
1640
1654
|
}
|
|
1641
1655
|
} else {
|
|
@@ -1652,66 +1666,151 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1652
1666
|
return c === "\n" || c === "\r";
|
|
1653
1667
|
};
|
|
1654
1668
|
/**
|
|
1655
|
-
*
|
|
1656
|
-
*
|
|
1669
|
+
* Walk a `#define` directive head once and produce everything both routing
|
|
1670
|
+
* and registration need: name range, optional params range, value range,
|
|
1671
|
+
* and whether the value parses as an `expression`.
|
|
1672
|
+
*
|
|
1673
|
+
* The replacement list is split three ways:
|
|
1674
|
+
*
|
|
1675
|
+
* - **AST path** (`isExpression = true`): value parses as `expression`.
|
|
1676
|
+
* Covers identifiers, literals, parenthesized sub-expressions, operator
|
|
1677
|
+
* expressions, function calls, top-level comma lists (per C99 §6.10.3).
|
|
1678
|
+
*
|
|
1679
|
+
* - **Legacy opaque path** (`isExpression = false`, no throw): the three
|
|
1680
|
+
* GLSL-ES-§3.4-legal-but-not-an-expression shapes with real-world use —
|
|
1681
|
+
* 1. empty value e.g. `#define COMMON_INCLUDED`
|
|
1682
|
+
* 2. single type/qualifier keyword e.g. `#define FxaaFloat float`
|
|
1683
|
+
* 3. type-qualifier list e.g. `#define TEX_PARAM(s) mediump sampler2D s`
|
|
1684
|
+
*
|
|
1685
|
+
* Note on X-macro support: the classical C X-macro pattern (a list
|
|
1686
|
+
* macro re-expanded with redefined `X(...)`) works fine — it uses
|
|
1687
|
+
* function-like macros + `\` line-continuation + `#undef`, all of
|
|
1688
|
+
* which Galacean supports. It does NOT require unbalanced parens.
|
|
1657
1689
|
*
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
1661
|
-
*
|
|
1662
|
-
*
|
|
1663
|
-
* by the GLSL driver via textual substitution and needs no AST.
|
|
1690
|
+
* - **Authoring error** (throws): every other shape that's not a valid
|
|
1691
|
+
* `expression`. Legal token sequences in theory but not used in real
|
|
1692
|
+
* GLSL — almost always author mistakes. We surface one uniform
|
|
1693
|
+
* diagnostic with the macro name and value text and let the user fix
|
|
1694
|
+
* their code instead of routing politely.
|
|
1664
1695
|
*
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1667
|
-
*
|
|
1668
|
-
*
|
|
1669
|
-
|
|
1696
|
+
* Unsupported shapes that throw (non-exhaustive — the predicate is
|
|
1697
|
+
* "the value doesn't reduce as `expression` and isn't one of the three
|
|
1698
|
+
* legacy shapes above"):
|
|
1699
|
+
* - leading bare punctuation `,` `;` `:` `?` `)` `]`
|
|
1700
|
+
* - trailing `,` or `;` e.g. `#define X a, b,`
|
|
1701
|
+
* - trailing binary / unary op `+` `-` `*` `/` `%` `&` `|` `^`
|
|
1702
|
+
* `<` `>` `=` `!` `~`
|
|
1703
|
+
* - trailing ternary fragment `?` or `:`
|
|
1704
|
+
* - unbalanced `[` / `]` e.g. `#define X a[b`
|
|
1705
|
+
* - unbalanced `(` / `)` e.g. `#define PAREN (`
|
|
1706
|
+
*
|
|
1707
|
+
* Returns `null` if the directive is malformed before the name. `cursor` is
|
|
1708
|
+
* the position past the last non-newline char (caller advances from there).
|
|
1709
|
+
*/ _proto._peekMacroDefine = function _peekMacroDefine() {
|
|
1670
1710
|
var src = this._source;
|
|
1671
1711
|
var len = src.length;
|
|
1672
|
-
// All position advancement goes through `_skipNonSemantic`, which honors
|
|
1673
|
-
// line-continuation (`\` + newline) and skips comments. This is critical:
|
|
1674
|
-
// `#define UV foo \\\n .field` is one logical directive whose value
|
|
1675
|
-
// contains `.field`, and `#define HP /* a.b */ highp` must not let the
|
|
1676
|
-
// `.` inside the comment trigger AST routing.
|
|
1677
1712
|
var i = Lexer._skipNonSemantic(src, this._currentIndex, len);
|
|
1678
|
-
|
|
1679
|
-
|
|
1713
|
+
if (!(i < len && BaseLexer.isAlpha(src.charCodeAt(i)))) return null;
|
|
1714
|
+
var nameStart = i;
|
|
1680
1715
|
while(i < len && BaseLexer.isAlnum(src.charCodeAt(i)))i++;
|
|
1681
|
-
|
|
1682
|
-
// Optional `(params)
|
|
1683
|
-
|
|
1716
|
+
var name = src.slice(nameStart, i);
|
|
1717
|
+
// Optional `(params)` glued to the name (function-like per C99 §6.10.3/10;
|
|
1718
|
+
// whitespace before `(` makes it object-like — `(` becomes part of value).
|
|
1719
|
+
var paramsLexeme;
|
|
1720
|
+
if (i < len && src.charCodeAt(i) === 40 /* '(' */ ) {
|
|
1721
|
+
var paramsStart = i;
|
|
1684
1722
|
var depth = 1;
|
|
1685
1723
|
i++;
|
|
1686
1724
|
while(i < len && depth > 0){
|
|
1687
1725
|
i = Lexer._skipNonSemantic(src, i, len);
|
|
1726
|
+
if (i >= len) break;
|
|
1688
1727
|
var c = src.charCodeAt(i);
|
|
1689
|
-
if (c === 10 || c === 13)
|
|
1728
|
+
if (c === 10 || c === 13) {
|
|
1729
|
+
// Unbalanced before newline — treat as malformed function-like.
|
|
1730
|
+
return {
|
|
1731
|
+
name: name,
|
|
1732
|
+
paramsLexeme: undefined,
|
|
1733
|
+
valueStart: i,
|
|
1734
|
+
valueEnd: i,
|
|
1735
|
+
cursor: i,
|
|
1736
|
+
isExpression: false
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1690
1739
|
if (c === 40) depth++;
|
|
1691
1740
|
else if (c === 41 /* ')' */ ) depth--;
|
|
1692
1741
|
i++;
|
|
1693
1742
|
}
|
|
1743
|
+
paramsLexeme = src.slice(paramsStart, i);
|
|
1694
1744
|
}
|
|
1695
|
-
//
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1745
|
+
// Walk the value once tracking what routing needs.
|
|
1746
|
+
var valueStart = i;
|
|
1747
|
+
var parenDepth = 0;
|
|
1748
|
+
var bracketDepth = 0;
|
|
1749
|
+
var firstStart = -1;
|
|
1750
|
+
var firstEnd = -1;
|
|
1751
|
+
var firstFollowedByParen = false;
|
|
1752
|
+
var topLevelLast = -1;
|
|
1700
1753
|
while(i < len){
|
|
1701
|
-
|
|
1702
|
-
if (
|
|
1754
|
+
var skipped = Lexer._skipNonSemantic(src, i, len);
|
|
1755
|
+
if (skipped !== i) {
|
|
1756
|
+
i = skipped;
|
|
1757
|
+
continue;
|
|
1758
|
+
}
|
|
1703
1759
|
var c1 = src.charCodeAt(i);
|
|
1704
|
-
if (c1 === 10 || c1 === 13) break;
|
|
1705
|
-
if (
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1760
|
+
if (c1 === 10 || c1 === 13) break;
|
|
1761
|
+
if (firstStart === -1) {
|
|
1762
|
+
firstStart = i;
|
|
1763
|
+
if (BaseLexer.isAlpha(c1)) {
|
|
1764
|
+
while(i < len && BaseLexer.isAlnum(src.charCodeAt(i)))i++;
|
|
1765
|
+
firstEnd = i;
|
|
1766
|
+
var after = Lexer._skipNonSemantic(src, i, len);
|
|
1767
|
+
firstFollowedByParen = after < len && src.charCodeAt(after) === 40;
|
|
1768
|
+
topLevelLast = firstEnd - 1;
|
|
1769
|
+
continue;
|
|
1770
|
+
}
|
|
1711
1771
|
}
|
|
1772
|
+
if (c1 === 40) parenDepth++;
|
|
1773
|
+
else if (c1 === 41) parenDepth--;
|
|
1774
|
+
else if (c1 === 91 /* [ */ ) bracketDepth++;
|
|
1775
|
+
else if (c1 === 93 /* ] */ ) bracketDepth--;
|
|
1776
|
+
if (parenDepth === 0 && bracketDepth === 0) topLevelLast = i;
|
|
1712
1777
|
i++;
|
|
1713
1778
|
}
|
|
1714
|
-
|
|
1779
|
+
var result = {
|
|
1780
|
+
name: name,
|
|
1781
|
+
paramsLexeme: paramsLexeme,
|
|
1782
|
+
valueStart: valueStart,
|
|
1783
|
+
valueEnd: i,
|
|
1784
|
+
cursor: i,
|
|
1785
|
+
isExpression: false
|
|
1786
|
+
};
|
|
1787
|
+
// Real-world legacy shapes:
|
|
1788
|
+
// 1. empty value, 2. single type/qualifier kw, 3. type-qualifier list.
|
|
1789
|
+
if (firstStart === -1) return result;
|
|
1790
|
+
if (firstEnd !== -1 && !firstFollowedByParen && Lexer._isNonExpressionLeadingKeyword(src.slice(firstStart, firstEnd))) {
|
|
1791
|
+
return result;
|
|
1792
|
+
}
|
|
1793
|
+
// Authoring errors. Anything that's neither a legal `expression` nor one
|
|
1794
|
+
// of the three legacy shapes above gets a single uniform diagnostic —
|
|
1795
|
+
// the user sees the macro name and the value text, that's enough to
|
|
1796
|
+
// locate and fix. We don't categorize further; the rule for users is
|
|
1797
|
+
// simply "value must be a valid GLSL expression".
|
|
1798
|
+
//
|
|
1799
|
+
// Legal expression starts: alnum (identifier / literal), `(` (group),
|
|
1800
|
+
// `.` (GLSL ES §4.1.4 leading-dot float literal like `.5`), `-`/`+`/`!`/`~`
|
|
1801
|
+
// (unary). Legal expression ends: alnum (identifier / literal), `)` (group
|
|
1802
|
+
// close), `]` (array-index close). Everything else at the head or
|
|
1803
|
+
// top-level tail is an authoring error.
|
|
1804
|
+
var head = src.charCodeAt(firstStart);
|
|
1805
|
+
var tail = topLevelLast >= 0 ? src.charCodeAt(topLevelLast) : 0;
|
|
1806
|
+
var headIllegal = !BaseLexer.isAlnum(head) && head !== 40 /* ( */ && head !== 46 /* . */ && head !== 45 /* - */ && head !== 43 /* + */ && head !== 33 /* ! */ && head !== 126; /* ~ */
|
|
1807
|
+
var tailIllegal = !BaseLexer.isAlnum(tail) && tail !== 41 /* ) */ && tail !== 93; /* ] */
|
|
1808
|
+
if (parenDepth !== 0 || bracketDepth !== 0 || headIllegal || tailIllegal) {
|
|
1809
|
+
var valueText = src.slice(firstStart, i).replace(/\s+/g, " ").trim();
|
|
1810
|
+
this.throwError(this.getShaderPosition(0), "#define " + name + ': invalid replacement list — not a valid GLSL expression ("' + valueText + '")');
|
|
1811
|
+
}
|
|
1812
|
+
result.isExpression = true;
|
|
1813
|
+
return result;
|
|
1715
1814
|
};
|
|
1716
1815
|
/** Consuming wrapper around `_skipNonSemantic` operating on the lexer's
|
|
1717
1816
|
* current position. Used by the `#define`-value scan state machine. Goes
|
|
@@ -1755,11 +1854,16 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1755
1854
|
this.advance(1);
|
|
1756
1855
|
}
|
|
1757
1856
|
var token = BaseToken.pool.get();
|
|
1758
|
-
|
|
1857
|
+
var lexeme = buffer.join("");
|
|
1858
|
+
this._currentMacroParamsLexeme = lexeme;
|
|
1859
|
+
// Value starts after the `)` we just consumed.
|
|
1860
|
+
this._currentMacroValueStart = this._currentIndex;
|
|
1861
|
+
token.set(Keyword.MACRO_DEFINE_PARAMS, lexeme, start);
|
|
1759
1862
|
return token;
|
|
1760
1863
|
};
|
|
1761
1864
|
/** Emit `MACRO_DEFINE_END` at the end of a `#define` value, consuming the newline. */ _proto._emitMacroDefineEnd = function _emitMacroDefineEnd() {
|
|
1762
1865
|
var start = this.getShaderPosition();
|
|
1866
|
+
var valueEnd = this._currentIndex;
|
|
1763
1867
|
var source = this._source;
|
|
1764
1868
|
if (this._currentIndex < source.length) {
|
|
1765
1869
|
var c = source.charCodeAt(this._currentIndex);
|
|
@@ -1769,37 +1873,29 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1769
1873
|
this.advance(1);
|
|
1770
1874
|
}
|
|
1771
1875
|
}
|
|
1772
|
-
|
|
1773
|
-
this._registerMacroDefine(this._source.slice(this._macroDefineDirectiveStart, this._currentIndex));
|
|
1876
|
+
this._registerMacroDefine(this._currentMacroName, this._currentMacroParamsLexeme, this._currentMacroValueStart, valueEnd);
|
|
1774
1877
|
this._inMacroDefineValue = false;
|
|
1775
1878
|
var token = BaseToken.pool.get();
|
|
1776
1879
|
token.set(Keyword.MACRO_DEFINE_END, "\n", start);
|
|
1777
1880
|
return token;
|
|
1778
1881
|
};
|
|
1779
|
-
//
|
|
1780
|
-
//
|
|
1781
|
-
//
|
|
1782
|
-
_proto._registerMacroDefine = function _registerMacroDefine(
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
// the next physical line onto this one. The regex's value group rejects
|
|
1786
|
-
// newlines, so without folding any multi-line directive (`#define X a \\\n + b`)
|
|
1787
|
-
// would NO MATCH and registration would silently fail.
|
|
1788
|
-
var folded = directive.replace(Lexer._lineContinuationReg, "");
|
|
1789
|
-
var m = Lexer._defineDirectiveReg.exec(folded);
|
|
1790
|
-
if (!m) return;
|
|
1791
|
-
var name = m[1];
|
|
1792
|
-
var paramsStr = m[3];
|
|
1793
|
-
var valueRaw = m[4];
|
|
1794
|
-
var params = paramsStr ? paramsStr.split(",").map(function(p) {
|
|
1882
|
+
// Register a `#define` directive. Both AST and legacy paths funnel through
|
|
1883
|
+
// here using ranges already extracted by `_peekMacroDefine` / the value
|
|
1884
|
+
// state machine — no re-parsing the directive text.
|
|
1885
|
+
_proto._registerMacroDefine = function _registerMacroDefine(name, paramsLexeme, valueStart, valueEnd) {
|
|
1886
|
+
var params = paramsLexeme ? paramsLexeme.slice(1, -1) // strip enclosing `(` `)`
|
|
1887
|
+
.split(",").map(function(p) {
|
|
1795
1888
|
return p.trim();
|
|
1796
1889
|
}).filter(Boolean) : [];
|
|
1797
|
-
|
|
1890
|
+
// Dedup key: normalized value text (same lexical view the token-stream
|
|
1891
|
+
// path sees — comments stripped, whitespace collapsed). Two `#define`s
|
|
1892
|
+
// with the same name but different value text produce different keys,
|
|
1893
|
+
// so disjoint-branch entries stay separate.
|
|
1894
|
+
var dedupKey = (paramsLexeme != null ? paramsLexeme : "") + "=" + Lexer._normalizeValueText(this._source, valueStart, valueEnd);
|
|
1798
1895
|
var info = {
|
|
1799
|
-
isFunction:
|
|
1800
|
-
name: name,
|
|
1896
|
+
isFunction: paramsLexeme !== undefined,
|
|
1801
1897
|
params: params,
|
|
1802
|
-
|
|
1898
|
+
dedupKey: dedupKey,
|
|
1803
1899
|
branch: this._branchStack.length === 0 ? EMPTY_BRANCH : this._branchStack.slice()
|
|
1804
1900
|
};
|
|
1805
1901
|
var arr = this.macroDefineList[name];
|
|
@@ -1809,14 +1905,11 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1809
1905
|
];
|
|
1810
1906
|
return;
|
|
1811
1907
|
}
|
|
1812
|
-
//
|
|
1813
|
-
//
|
|
1814
|
-
// picks the visible one); same branch + same shape → drop.
|
|
1908
|
+
// Same key + same branch → duplicate (re-include). Different branches stay
|
|
1909
|
+
// separate so the visibility filter picks the right entry at each call site.
|
|
1815
1910
|
for(var i = 0, n = arr.length; i < n; i++){
|
|
1816
1911
|
var e = arr[i];
|
|
1817
|
-
if (e.
|
|
1818
|
-
return p === info.params[idx];
|
|
1819
|
-
}) && Lexer.sameBranch(e.branch, info.branch)) return;
|
|
1912
|
+
if (e.dedupKey === dedupKey && Lexer.sameBranch(e.branch, info.branch)) return;
|
|
1820
1913
|
}
|
|
1821
1914
|
arr.push(info);
|
|
1822
1915
|
};
|
|
@@ -1846,6 +1939,8 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1846
1939
|
// Bypass MACRO_CALL classification for this one word. Used for the name of
|
|
1847
1940
|
// a `#define` directive so redefining a known macro still yields a declarer ID.
|
|
1848
1941
|
this._macroDefineExpectsNameToken = false;
|
|
1942
|
+
this._currentMacroName = word;
|
|
1943
|
+
this._currentMacroParamsLexeme = undefined;
|
|
1849
1944
|
// C99 §6.10.3/3: the macro is function-like only when `(` appears *immediately*
|
|
1850
1945
|
// after the name (no intervening whitespace). `#define FOO (1+2)` is
|
|
1851
1946
|
// object-like with value `(1+2)`, not a function-like macro `FOO()` with
|
|
@@ -1853,6 +1948,10 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1853
1948
|
// on the next `scanToken`, so a space-separated `(` stays part of the value.
|
|
1854
1949
|
if (this._inMacroDefineValue) {
|
|
1855
1950
|
this._macroDefineExpectsParamsToken = this.getCurChar() === "(";
|
|
1951
|
+
// For object-like macros, the value begins where the cursor is now
|
|
1952
|
+
// (after the name, before whitespace skipping). Function-like macros
|
|
1953
|
+
// overwrite this in `_scanMacroDefineParams` after capturing `(...)`.
|
|
1954
|
+
this._currentMacroValueStart = this._currentIndex;
|
|
1856
1955
|
}
|
|
1857
1956
|
token.set(ETokenType.ID, word, start);
|
|
1858
1957
|
} else if (this._isVisibleMacro(word)) {
|
|
@@ -1992,6 +2091,12 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1992
2091
|
}
|
|
1993
2092
|
return true;
|
|
1994
2093
|
};
|
|
2094
|
+
/** GLSL type / qualifier keywords that aren't expression starters when standing alone.
|
|
2095
|
+
* `true` / `false` are excluded — they're `primary_expression` literals.
|
|
2096
|
+
* `#`-prefixed entries are excluded — they're preprocessor directive names. */ Lexer._isNonExpressionLeadingKeyword = function _isNonExpressionLeadingKeyword(lexeme) {
|
|
2097
|
+
var kw = Lexer._lexemeTable[lexeme];
|
|
2098
|
+
return kw !== undefined && kw !== Keyword.True && kw !== Keyword.False && !lexeme.startsWith("#");
|
|
2099
|
+
};
|
|
1995
2100
|
/**
|
|
1996
2101
|
* If `i` points at a `\` immediately followed by a newline (`\n`, `\r`, or
|
|
1997
2102
|
* `\r\n`), return the index just past the pair (a single atom in the C/GLSL
|
|
@@ -1999,8 +2104,7 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
1999
2104
|
* source of truth for line-continuation detection — callers along the
|
|
2000
2105
|
* directive-scanning path (`_skipNonSemantic`, `_scanUtilBreakLine`,
|
|
2001
2106
|
* `_scanMacroDefineParams`) all delegate here so the rule stays in one
|
|
2002
|
-
* place.
|
|
2003
|
-
* used by `_registerMacroDefine` for one-shot folding.
|
|
2107
|
+
* place.
|
|
2004
2108
|
*/ Lexer._skipLineContinuation = function _skipLineContinuation(src, i, len) {
|
|
2005
2109
|
if (src.charCodeAt(i) !== 92 /* '\\' */ || i + 1 >= len) return i;
|
|
2006
2110
|
var n = src.charCodeAt(i + 1);
|
|
@@ -2043,6 +2147,34 @@ var ParserUtils = /*#__PURE__*/ function() {
|
|
|
2043
2147
|
}
|
|
2044
2148
|
return i;
|
|
2045
2149
|
};
|
|
2150
|
+
/** Render a `[start, end)` value range as space-separated significant chars,
|
|
2151
|
+
* using the same comment / line-continuation rules `_skipNonSemantic`
|
|
2152
|
+
* applies on the token-stream path. Used as the dedup key body. */ Lexer._normalizeValueText = function _normalizeValueText(src, start, end) {
|
|
2153
|
+
var out = "";
|
|
2154
|
+
var i = start;
|
|
2155
|
+
var pendingSpace = false;
|
|
2156
|
+
while(i < end){
|
|
2157
|
+
var skipped = Lexer._skipNonSemantic(src, i, end);
|
|
2158
|
+
if (skipped !== i) {
|
|
2159
|
+
pendingSpace = out.length > 0;
|
|
2160
|
+
i = skipped;
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
var c = src.charCodeAt(i);
|
|
2164
|
+
if (c === 32 || c === 9) {
|
|
2165
|
+
pendingSpace = out.length > 0;
|
|
2166
|
+
i++;
|
|
2167
|
+
continue;
|
|
2168
|
+
}
|
|
2169
|
+
if (pendingSpace) {
|
|
2170
|
+
out += " ";
|
|
2171
|
+
pendingSpace = false;
|
|
2172
|
+
}
|
|
2173
|
+
out += src[i];
|
|
2174
|
+
i++;
|
|
2175
|
+
}
|
|
2176
|
+
return out;
|
|
2177
|
+
};
|
|
2046
2178
|
return Lexer;
|
|
2047
2179
|
}(BaseLexer);
|
|
2048
2180
|
Lexer._lexemeTable = {
|
|
@@ -2119,12 +2251,6 @@ Lexer._lexemeTable = {
|
|
|
2119
2251
|
"#endif": Keyword.MACRO_ENDIF,
|
|
2120
2252
|
"#undef": Keyword.MACRO_UNDEF
|
|
2121
2253
|
};
|
|
2122
|
-
// Single source of truth for `#define` parsing — fed from both AST and legacy paths.
|
|
2123
|
-
Lexer._defineDirectiveReg = /^\s*#define\s+(\w+)[ ]*(\(([^)]*)\))?(?:[ \t]+([^\n\r]*?))?\s*$/;
|
|
2124
|
-
// Bare identifier or call form only — mixed-operator values reject.
|
|
2125
|
-
Lexer._referenceReg = /^([a-zA-Z_]\w*)(?:\s*\(.*\))?$/;
|
|
2126
|
-
// C preprocessor line continuation.
|
|
2127
|
-
Lexer._lineContinuationReg = /\\(?:\r\n|\n|\r)/g;
|
|
2128
2254
|
// Synthetic `__if_<n>` per `#if` — polarity flip makes `#else` mutually exclusive in `isVisibleFrom`.
|
|
2129
2255
|
Lexer._ifCounter = 0;
|
|
2130
2256
|
|
|
@@ -4821,34 +4947,13 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4821
4947
|
var child = this.children[0];
|
|
4822
4948
|
var referenceGlobalSymbolNames = this.referenceGlobalSymbolNames;
|
|
4823
4949
|
var symbols = this._symbols;
|
|
4824
|
-
|
|
4825
|
-
var needFindNames
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
// At a MACRO_CALL use site, also probe the macro name itself so
|
|
4829
|
-
// the sibling-arm declaration is marked as referenced and codegen
|
|
4830
|
-
// keeps it. Grammar half of the fix is in 87cb2b5f0.
|
|
4831
|
-
var macroNameAsVarLookup = null;
|
|
4832
|
-
if (_instanceof(child, BaseToken)) {
|
|
4833
|
-
needFindNames = [
|
|
4834
|
-
child.lexeme
|
|
4835
|
-
];
|
|
4836
|
-
} else {
|
|
4837
|
-
var callSymbol = child;
|
|
4838
|
-
needFindNames = callSymbol.referenceSymbolNames;
|
|
4839
|
-
var macroName = callSymbol.macroName;
|
|
4840
|
-
if (macroName && needFindNames.indexOf(macroName) === -1) {
|
|
4841
|
-
needFindNames = needFindNames.concat(macroName);
|
|
4842
|
-
macroNameAsVarLookup = macroName;
|
|
4843
|
-
}
|
|
4844
|
-
}
|
|
4950
|
+
// Real references — every name must resolve; miss is an authoring error.
|
|
4951
|
+
var needFindNames = _instanceof(child, BaseToken) ? [
|
|
4952
|
+
child.lexeme
|
|
4953
|
+
] : child.referenceSymbolNames;
|
|
4845
4954
|
for(var i = 0; i < needFindNames.length; i++){
|
|
4846
4955
|
var name = needFindNames[i];
|
|
4847
|
-
|
|
4848
|
-
// so cross-arm shadowing can resolve the sibling-arm declaration.
|
|
4849
|
-
if (sa.macroDefineList[name] && name !== macroNameAsVarLookup) {
|
|
4850
|
-
continue;
|
|
4851
|
-
}
|
|
4956
|
+
if (sa.macroDefineList[name]) continue;
|
|
4852
4957
|
// only `macro_call` CFG can reference fnSymbols, others fnSymbols are referenced in `function_call_generic` CFG
|
|
4853
4958
|
if (!_instanceof(child, BaseToken) && BuiltinFunction.isExist(name)) {
|
|
4854
4959
|
continue;
|
|
@@ -4858,31 +4963,24 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4858
4963
|
this.typeInfo = builtinVar.type;
|
|
4859
4964
|
continue;
|
|
4860
4965
|
}
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
// member type). Skip type inference for those and keep TypeAny.
|
|
4870
|
-
if (_instanceof(child, BaseToken) || !child.hasAstValue) {
|
|
4871
|
-
var _symbols__dataType;
|
|
4872
|
-
this.typeInfo = (_symbols__dataType = symbols[0].dataType) == null ? void 0 : _symbols__dataType.type;
|
|
4873
|
-
}
|
|
4874
|
-
var currentScopeSymbol = sa.symbolTableStack.scope.getSymbol(lookupSymbol, true);
|
|
4875
|
-
if (currentScopeSymbol) {
|
|
4876
|
-
if ((_instanceof(currentScopeSymbol, FnSymbol) || currentScopeSymbol.isGlobalVariable) && referenceGlobalSymbolNames.indexOf(name) === -1) {
|
|
4877
|
-
referenceGlobalSymbolNames.push(name);
|
|
4878
|
-
}
|
|
4879
|
-
} else if (symbols.some(function(s) {
|
|
4880
|
-
return _instanceof(s, FnSymbol) || s.isGlobalVariable;
|
|
4881
|
-
}) && referenceGlobalSymbolNames.indexOf(name) === -1) {
|
|
4882
|
-
referenceGlobalSymbolNames.push(name);
|
|
4883
|
-
}
|
|
4966
|
+
var hit = VariableIdentifier._lookupAndMarkGlobalReference(sa, name, symbols, referenceGlobalSymbolNames, this.location);
|
|
4967
|
+
// Expression-style macros have their own value AST; its real type isn't
|
|
4968
|
+
// the type of any single `referenceSymbolNames` entry (`v` in `v.v_uv`
|
|
4969
|
+
// is a `Varyings` struct but the macro call site's type should be the
|
|
4970
|
+
// member type). Skip type inference for those and keep TypeAny.
|
|
4971
|
+
if (hit && (_instanceof(child, BaseToken) || !child.hasAstValue)) {
|
|
4972
|
+
var _symbols__dataType;
|
|
4973
|
+
this.typeInfo = (_symbols__dataType = symbols[0].dataType) == null ? void 0 : _symbols__dataType.type;
|
|
4884
4974
|
}
|
|
4885
4975
|
}
|
|
4976
|
+
// FXAA-style cross-arm shadowing: at a MACRO_CALL use site, silently
|
|
4977
|
+
// probe the macro name itself so any sibling-arm `var` declaration is
|
|
4978
|
+
// marked as referenced and codegen keeps it. Miss is the common
|
|
4979
|
+
// single-arm case — no warning, no type inference. Grammar half of the
|
|
4980
|
+
// cross-arm fix is in 87cb2b5f0.
|
|
4981
|
+
if (!_instanceof(child, BaseToken)) {
|
|
4982
|
+
VariableIdentifier._probeCrossArmShadowing(sa, child, needFindNames, symbols, referenceGlobalSymbolNames);
|
|
4983
|
+
}
|
|
4886
4984
|
};
|
|
4887
4985
|
_proto.codeGen = function codeGen(visitor) {
|
|
4888
4986
|
return this.setCache(visitor.visitVariableIdentifier(this));
|
|
@@ -4895,6 +4993,43 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
4895
4993
|
return child.codeGen(visitor);
|
|
4896
4994
|
}
|
|
4897
4995
|
};
|
|
4996
|
+
/** Run the cross-arm shadowing probe for a MACRO_CALL site. No-op when the
|
|
4997
|
+
* probe isn't meaningful: no macro name, name already resolved as a real
|
|
4998
|
+
* reference, or name is a builtin (builtins can't be shadowed by a
|
|
4999
|
+
* sibling-arm decl). */ VariableIdentifier._probeCrossArmShadowing = function _probeCrossArmShadowing(sa, child, needFindNames, symbols, referenceGlobalSymbolNames) {
|
|
5000
|
+
var macroName = child.macroName;
|
|
5001
|
+
if (!macroName) return;
|
|
5002
|
+
if (needFindNames.indexOf(macroName) !== -1) return; // already looked up as a real reference
|
|
5003
|
+
if (BuiltinFunction.isExist(macroName) || BuiltinVariable.getVar(macroName)) return; // builtins can't be shadowed
|
|
5004
|
+
VariableIdentifier._lookupAndMarkGlobalReference(sa, macroName, symbols, referenceGlobalSymbolNames, null);
|
|
5005
|
+
};
|
|
5006
|
+
/** Look up `name` in the symbol stack and, if a global var/fn declaration
|
|
5007
|
+
* exists, push it into `referenceGlobalSymbolNames`. Returns `true` iff
|
|
5008
|
+
* the lookup hit (caller can then derive type info). When `missWarnLoc`
|
|
5009
|
+
* is non-null, a miss reports a "declared before used" warning; pass
|
|
5010
|
+
* `null` for silent probes (e.g. FXAA-style cross-arm shadowing).
|
|
5011
|
+
*
|
|
5012
|
+
* Mutation contract: `symbols` is used as scratch storage — `lookupAll`
|
|
5013
|
+
* clears and refills it. On hit, the caller may read `symbols[0]` for
|
|
5014
|
+
* type info before the next call overwrites the contents. */ VariableIdentifier._lookupAndMarkGlobalReference = function _lookupAndMarkGlobalReference(sa, name, symbols, referenceGlobalSymbolNames, missWarnLoc) {
|
|
5015
|
+
var lookupSymbol = SemanticAnalyzer._lookupSymbol;
|
|
5016
|
+
lookupSymbol.set(name, ESymbolType.Any);
|
|
5017
|
+
sa.symbolTableStack.lookupAll(lookupSymbol, true, symbols);
|
|
5018
|
+
if (!symbols.length) {
|
|
5019
|
+
if (missWarnLoc) {
|
|
5020
|
+
sa.reportWarning(missWarnLoc, 'Please sure the identifier "' + name + '" will be declared before used.');
|
|
5021
|
+
}
|
|
5022
|
+
return false;
|
|
5023
|
+
}
|
|
5024
|
+
var currentScopeSymbol = sa.symbolTableStack.scope.getSymbol(lookupSymbol, true);
|
|
5025
|
+
var isGlobal = currentScopeSymbol ? _instanceof(currentScopeSymbol, FnSymbol) || currentScopeSymbol.isGlobalVariable : symbols.some(function(s) {
|
|
5026
|
+
return _instanceof(s, FnSymbol) || s.isGlobalVariable;
|
|
5027
|
+
});
|
|
5028
|
+
if (isGlobal && referenceGlobalSymbolNames.indexOf(name) === -1) {
|
|
5029
|
+
referenceGlobalSymbolNames.push(name);
|
|
5030
|
+
}
|
|
5031
|
+
return true;
|
|
5032
|
+
};
|
|
4898
5033
|
return VariableIdentifier;
|
|
4899
5034
|
}(TreeNode);
|
|
4900
5035
|
ASTNode.VariableIdentifier = VariableIdentifier;
|
|
@@ -5151,18 +5286,16 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5151
5286
|
MacroBranch = __decorate([
|
|
5152
5287
|
ASTNodeDecorator(NoneTerminal.macro_branch)
|
|
5153
5288
|
], MacroBranch);
|
|
5154
|
-
var MacroCallSymbol = /*#__PURE__*/ function(
|
|
5155
|
-
_inherits(MacroCallSymbol,
|
|
5289
|
+
var MacroCallSymbol = /*#__PURE__*/ function(TreeNode1) {
|
|
5290
|
+
_inherits(MacroCallSymbol, TreeNode1);
|
|
5156
5291
|
function MacroCallSymbol() {
|
|
5157
5292
|
var _this;
|
|
5158
|
-
_this =
|
|
5293
|
+
_this = TreeNode1.apply(this, arguments) || this, _this.referenceSymbolNames = [], /** True iff every `MacroDefineInfo` visible from this call site's branch
|
|
5159
5294
|
* has a `valueAst` (i.e. was parsed via the `macro_define` CFG rule).
|
|
5160
5295
|
* Call sites use this to skip naive type inference: an AST-form macro
|
|
5161
5296
|
* drives the call site's type through its own value subtree, not through
|
|
5162
5297
|
* a root of `referenceSymbolNames`. Mixed forms across branches → false,
|
|
5163
|
-
* fall back to legacy inference. */ _this.hasAstValue = false, /**
|
|
5164
|
-
* Used by `MacroCallFunction` codegen to pick between the two call shapes
|
|
5165
|
-
* — object-like-macro-as-function-name vs true function-like macro. */ _this.isFunctionLikeMacro = false;
|
|
5298
|
+
* 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;
|
|
5166
5299
|
return _this;
|
|
5167
5300
|
}
|
|
5168
5301
|
var _proto = MacroCallSymbol.prototype;
|
|
@@ -5170,6 +5303,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5170
5303
|
this.referenceSymbolNames.length = 0;
|
|
5171
5304
|
this.hasAstValue = false;
|
|
5172
5305
|
this.isFunctionLikeMacro = false;
|
|
5306
|
+
this.aliasesNonBuiltinIdent = false;
|
|
5173
5307
|
};
|
|
5174
5308
|
_proto.semanticAnalyze = function semanticAnalyze(sa) {
|
|
5175
5309
|
var nameToken = this.children[0];
|
|
@@ -5187,6 +5321,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5187
5321
|
var visibleCount = 0;
|
|
5188
5322
|
var allAst = true;
|
|
5189
5323
|
var isFn = false;
|
|
5324
|
+
var allAliasNonBuiltinIdent = true;
|
|
5190
5325
|
if (defList) {
|
|
5191
5326
|
for(var i = 0, n = defList.length; i < n; i++){
|
|
5192
5327
|
var info = defList[i];
|
|
@@ -5194,8 +5329,30 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5194
5329
|
visibleCount++;
|
|
5195
5330
|
if (info.valueAst == null) allAst = false;
|
|
5196
5331
|
if (info.isFunction) isFn = true;
|
|
5197
|
-
|
|
5198
|
-
|
|
5332
|
+
// Harvest references from the value AST. Legacy-form macros (no
|
|
5333
|
+
// `valueAst`) hold non-expression token sequences with no user
|
|
5334
|
+
// identifiers, so nothing to collect.
|
|
5335
|
+
if (info.valueAst) {
|
|
5336
|
+
MacroCallSymbol._collectIdentifierRefs(info.valueAst, info.params, refs);
|
|
5337
|
+
}
|
|
5338
|
+
// aliasesNonBuiltinIdent: macro replacement is a single non-builtin
|
|
5339
|
+
// identifier — best-effort proxy for "this macro call site aliases a
|
|
5340
|
+
// user fn", since uniform/const aliases would surface as a GLSL
|
|
5341
|
+
// compile error later anyway. Keyword replacements (`vec3`, `mat4`)
|
|
5342
|
+
// reach here with `valueAst === undefined` (opaque path), so they
|
|
5343
|
+
// automatically fail without an explicit keyword guard.
|
|
5344
|
+
if (info.isFunction || !info.valueAst) {
|
|
5345
|
+
allAliasNonBuiltinIdent = false;
|
|
5346
|
+
} else {
|
|
5347
|
+
var leadingIdent = ParserUtils.unwrapBareIdentifier(info.valueAst, {
|
|
5348
|
+
allowParens: false
|
|
5349
|
+
});
|
|
5350
|
+
var leadingChild = leadingIdent == null ? void 0 : leadingIdent.children[0];
|
|
5351
|
+
var leadingId = _instanceof(leadingChild, BaseToken) ? leadingChild.lexeme : undefined;
|
|
5352
|
+
if (!leadingId || BuiltinFunction.isExist(leadingId)) {
|
|
5353
|
+
allAliasNonBuiltinIdent = false;
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5199
5356
|
}
|
|
5200
5357
|
}
|
|
5201
5358
|
// Require *every* visible entry to be AST-form before taking the AST
|
|
@@ -5204,6 +5361,25 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5204
5361
|
// instead of polluting the call site with TypeAny.
|
|
5205
5362
|
this.hasAstValue = visibleCount > 0 && allAst;
|
|
5206
5363
|
this.isFunctionLikeMacro = isFn;
|
|
5364
|
+
this.aliasesNonBuiltinIdent = visibleCount > 0 && allAliasNonBuiltinIdent;
|
|
5365
|
+
};
|
|
5366
|
+
/** Push every leaf `VariableIdentifier`'s lexeme into `out`, skipping
|
|
5367
|
+
* function-like parameter names (local to the macro, not call-site refs)
|
|
5368
|
+
* and duplicates. */ MacroCallSymbol._collectIdentifierRefs = function _collectIdentifierRefs(node, params, out) {
|
|
5369
|
+
if (_instanceof(node, VariableIdentifier)) {
|
|
5370
|
+
var child = node.children[0];
|
|
5371
|
+
if (_instanceof(child, BaseToken)) {
|
|
5372
|
+
var name = child.lexeme;
|
|
5373
|
+
if (params.indexOf(name) === -1 && out.indexOf(name) === -1) out.push(name);
|
|
5374
|
+
}
|
|
5375
|
+
return;
|
|
5376
|
+
}
|
|
5377
|
+
var children = node.children;
|
|
5378
|
+
if (!children) return;
|
|
5379
|
+
for(var i = 0, n = children.length; i < n; i++){
|
|
5380
|
+
var c = children[i];
|
|
5381
|
+
if (_instanceof(c, TreeNode)) MacroCallSymbol._collectIdentifierRefs(c, params, out);
|
|
5382
|
+
}
|
|
5207
5383
|
};
|
|
5208
5384
|
return MacroCallSymbol;
|
|
5209
5385
|
}(TreeNode);
|
|
@@ -5215,7 +5391,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5215
5391
|
_inherits(MacroCallFunction, TreeNode);
|
|
5216
5392
|
function MacroCallFunction() {
|
|
5217
5393
|
var _this;
|
|
5218
|
-
_this = TreeNode.apply(this, arguments) || this, _this.referenceSymbolNames = [], _this.macroName = "", _this.hasAstValue = false, _this.isFunctionLikeMacro = false;
|
|
5394
|
+
_this = TreeNode.apply(this, arguments) || this, _this.referenceSymbolNames = [], _this.macroName = "", _this.hasAstValue = false, _this.isFunctionLikeMacro = false, _this.aliasesNonBuiltinIdent = false;
|
|
5219
5395
|
return _this;
|
|
5220
5396
|
}
|
|
5221
5397
|
var _proto = MacroCallFunction.prototype;
|
|
@@ -5224,6 +5400,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5224
5400
|
this.macroName = "";
|
|
5225
5401
|
this.hasAstValue = false;
|
|
5226
5402
|
this.isFunctionLikeMacro = false;
|
|
5403
|
+
this.aliasesNonBuiltinIdent = false;
|
|
5227
5404
|
};
|
|
5228
5405
|
_proto.semanticAnalyze = function semanticAnalyze(sa) {
|
|
5229
5406
|
var child = this.children[0];
|
|
@@ -5231,6 +5408,7 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5231
5408
|
this.macroName = child.macroName;
|
|
5232
5409
|
this.hasAstValue = child.hasAstValue;
|
|
5233
5410
|
this.isFunctionLikeMacro = child.isFunctionLikeMacro;
|
|
5411
|
+
this.aliasesNonBuiltinIdent = child.aliasesNonBuiltinIdent;
|
|
5234
5412
|
};
|
|
5235
5413
|
_proto.codeGen = function codeGen(visitor) {
|
|
5236
5414
|
return this.setCache(visitor.visitMacroCallFunction(this));
|
|
@@ -5266,7 +5444,10 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5266
5444
|
params = ParserUtils.parseMacroParamList(children[2].lexeme);
|
|
5267
5445
|
valueIdx = 3;
|
|
5268
5446
|
}
|
|
5269
|
-
|
|
5447
|
+
// Grammar's macro_define value is `expression` (not `assignment_expression`),
|
|
5448
|
+
// so the value child is always an `Expression` wrapper — even for a single
|
|
5449
|
+
// assignment-expression value, which appears as `Expression > AssignmentExpression`.
|
|
5450
|
+
if (_instanceof(children[valueIdx], Expression)) {
|
|
5270
5451
|
this.valueExpression = children[valueIdx];
|
|
5271
5452
|
}
|
|
5272
5453
|
// The Lexer already registered a regex-derived entry for this directive.
|
|
@@ -5289,14 +5470,14 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5289
5470
|
if (upgradable) {
|
|
5290
5471
|
upgradable.valueAst = this.valueExpression;
|
|
5291
5472
|
} else {
|
|
5292
|
-
// No matching preprocessor entry (
|
|
5293
|
-
//
|
|
5473
|
+
// No matching preprocessor entry (lexer fed directly, no
|
|
5474
|
+
// `Preprocessor.parse` pass). Synthetic key based on shape is enough
|
|
5475
|
+
// — this path's only dedup unit is this AST-direct registration.
|
|
5294
5476
|
var info = {
|
|
5295
5477
|
isFunction: this.isFunction,
|
|
5296
|
-
name: this.macroName,
|
|
5297
5478
|
params: params,
|
|
5298
5479
|
valueAst: this.valueExpression,
|
|
5299
|
-
|
|
5480
|
+
dedupKey: this.macroName + "#ast/" + (this.isFunction ? params.join(",") : ""),
|
|
5300
5481
|
branch: definingBranch
|
|
5301
5482
|
};
|
|
5302
5483
|
if (entries) entries.push(info);
|
|
@@ -5304,6 +5485,13 @@ var TreeNode = /*#__PURE__*/ function() {
|
|
|
5304
5485
|
info
|
|
5305
5486
|
];
|
|
5306
5487
|
}
|
|
5488
|
+
// Close the form-param scope pushed at `MACRO_DEFINE_PARAMS` shift. By
|
|
5489
|
+
// the time this reduce fires, every `VariableIdentifier` inside the
|
|
5490
|
+
// value expression has already resolved against the params. Object-like
|
|
5491
|
+
// macros never pushed a scope, so nothing to pop.
|
|
5492
|
+
if (this.isFunction) {
|
|
5493
|
+
sa.popScope();
|
|
5494
|
+
}
|
|
5307
5495
|
};
|
|
5308
5496
|
_proto.codeGen = function codeGen(visitor) {
|
|
5309
5497
|
return this.setCache(visitor.visitMacroDefine(this));
|
|
@@ -5531,30 +5719,24 @@ var TempArray = /*#__PURE__*/ function() {
|
|
|
5531
5719
|
if (_instanceof(paramList, ASTNode.FunctionCallParameterList)) {
|
|
5532
5720
|
var astNodes = paramList.paramNodes;
|
|
5533
5721
|
var context = VisitorContext.context;
|
|
5534
|
-
//
|
|
5535
|
-
//
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
// `macroDefineList[name][*].isFunction` and carries the definition shape.
|
|
5549
|
-
var params = node.isFunctionLikeMacro ? astNodes : astNodes.filter(function(arg) {
|
|
5550
|
-
if (_instanceof(arg, ASTNode.AssignmentExpression)) {
|
|
5551
|
-
var variableParam = ParserUtils.unwrapNodeByType(arg, NoneTerminal.variable_identifier);
|
|
5552
|
-
if (variableParam && typeof variableParam.typeInfo === "string" && context.getStructRole(variableParam.typeInfo)) {
|
|
5553
|
-
return false;
|
|
5722
|
+
// Drop bare IO-struct args only when the macro aliases a user fn (whose
|
|
5723
|
+
// formal was flattened). All other shapes preserve args verbatim.
|
|
5724
|
+
var params;
|
|
5725
|
+
if (node.isFunctionLikeMacro || !node.aliasesNonBuiltinIdent) {
|
|
5726
|
+
params = astNodes;
|
|
5727
|
+
} else {
|
|
5728
|
+
params = astNodes.filter(function(arg) {
|
|
5729
|
+
if (_instanceof(arg, ASTNode.AssignmentExpression)) {
|
|
5730
|
+
var variableParam = ParserUtils.unwrapBareIdentifier(arg, {
|
|
5731
|
+
allowParens: false
|
|
5732
|
+
});
|
|
5733
|
+
if (variableParam && typeof variableParam.typeInfo === "string" && context.getStructRole(variableParam.typeInfo)) {
|
|
5734
|
+
return false;
|
|
5735
|
+
}
|
|
5554
5736
|
}
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
}
|
|
5737
|
+
return true;
|
|
5738
|
+
});
|
|
5739
|
+
}
|
|
5558
5740
|
var paramsCode = "";
|
|
5559
5741
|
for(var i = 0, length = params.length; i < length; i++){
|
|
5560
5742
|
var argNode = params[i];
|
|
@@ -6904,9 +7086,14 @@ ShaderInstructionEncoder._FUNC_MACRO_RE = /^(\w+)\(([^)]*)\)\s*(.*)/;
|
|
|
6904
7086
|
/** Resolve shift-reduce/reduce-reduce conflict detect */ _proto._addAction = function _addAction(table, terminal, action) {
|
|
6905
7087
|
var exist = table.get(terminal);
|
|
6906
7088
|
if (exist && !GrammarUtils.isActionEqual(exist, action)) {
|
|
6907
|
-
//
|
|
6908
|
-
|
|
6909
|
-
|
|
7089
|
+
// Known shift-preferred conflicts (see TargetParser.y `%expect 2`).
|
|
7090
|
+
// Enforce shift regardless of the order `_inferNextState` registers
|
|
7091
|
+
// actions: when `exist` is already Shift and `action` is Reduce, keep
|
|
7092
|
+
// `exist` (early-return); the reverse order (`exist` Reduce, `action`
|
|
7093
|
+
// Shift) falls through to `table.set` below and Shift overwrites
|
|
7094
|
+
// Reduce. Order-independent by construction.
|
|
7095
|
+
if (LALR1._isKnownShiftPreferred(terminal, exist, action)) {
|
|
7096
|
+
if (exist.action === EAction.Shift && action.action === EAction.Reduce) return;
|
|
6910
7097
|
} else {
|
|
6911
7098
|
console.warn("conflict detect: <Terminal " + GrammarUtils.toString(terminal) + "> \n", GrammarUtils.printAction(exist), "\n", GrammarUtils.printAction(action));
|
|
6912
7099
|
}
|
|
@@ -6960,6 +7147,22 @@ ShaderInstructionEncoder._FUNC_MACRO_RE = /^(\w+)\(([^)]*)\)\s*(.*)/;
|
|
|
6960
7147
|
this._firstSetNTStack.pop();
|
|
6961
7148
|
return firstSet;
|
|
6962
7149
|
};
|
|
7150
|
+
// Catalog of expected shift/reduce conflicts. Each entry must correspond to
|
|
7151
|
+
// one of TargetParser.y's `%expect`-ed conflicts; any new conflict not in
|
|
7152
|
+
// this list falls through to the verbose `conflict detect` warning so the
|
|
7153
|
+
// grammar/runtime drift is loud rather than silent.
|
|
7154
|
+
// - ELSE: dangling-else, bind to nearest `if`
|
|
7155
|
+
// - '(' + `type_specifier_nonarray → macro_call_symbol`: macro-as-type-alias
|
|
7156
|
+
// (#2974), prefer the expression-position `macro_call_function` over the
|
|
7157
|
+
// type-position reduce
|
|
7158
|
+
LALR1._isKnownShiftPreferred = function _isKnownShiftPreferred(terminal, exist, action) {
|
|
7159
|
+
if (terminal === Keyword.ELSE) return true;
|
|
7160
|
+
if (terminal !== ETokenType.LEFT_PAREN) return false;
|
|
7161
|
+
var reduce = exist.action === EAction.Reduce ? exist : action.action === EAction.Reduce ? action : null;
|
|
7162
|
+
if (!reduce) return false;
|
|
7163
|
+
var prod = Production.pool.get(reduce.target);
|
|
7164
|
+
return !!prod && prod.goal === NoneTerminal.type_specifier_nonarray && prod.derivation.length === 1 && prod.derivation[0] === NoneTerminal.macro_call_symbol;
|
|
7165
|
+
};
|
|
6963
7166
|
return LALR1;
|
|
6964
7167
|
}();
|
|
6965
7168
|
|
|
@@ -7032,14 +7235,14 @@ var productionAndRules = [].concat(GrammarUtils.createProductionWithOptions(None
|
|
|
7032
7235
|
[
|
|
7033
7236
|
Keyword.MACRO_DEFINE,
|
|
7034
7237
|
ETokenType.ID,
|
|
7035
|
-
NoneTerminal.
|
|
7238
|
+
NoneTerminal.expression,
|
|
7036
7239
|
Keyword.MACRO_DEFINE_END
|
|
7037
7240
|
],
|
|
7038
7241
|
[
|
|
7039
7242
|
Keyword.MACRO_DEFINE,
|
|
7040
7243
|
ETokenType.ID,
|
|
7041
7244
|
Keyword.MACRO_DEFINE_PARAMS,
|
|
7042
|
-
NoneTerminal.
|
|
7245
|
+
NoneTerminal.expression,
|
|
7043
7246
|
Keyword.MACRO_DEFINE_END
|
|
7044
7247
|
]
|
|
7045
7248
|
], ASTNode.MacroDefine.pool), GrammarUtils.createProductionWithOptions(NoneTerminal.macro_call_symbol, [
|
|
@@ -8406,6 +8609,19 @@ var addTranslationRule = function(sa) {
|
|
|
8406
8609
|
var actionInfo = this.stateActionTable.get(token.type);
|
|
8407
8610
|
if ((actionInfo == null ? void 0 : actionInfo.action) === EAction.Shift) {
|
|
8408
8611
|
traceBackStack.push(token, actionInfo.target);
|
|
8612
|
+
// Function-like `#define` form params live in a scope wrapping the
|
|
8613
|
+
// value AST, mirroring how `function_header` opens a scope for GLSL
|
|
8614
|
+
// function parameters. Push on shift of `MACRO_DEFINE_PARAMS`; the
|
|
8615
|
+
// matching `popScope` runs when `MacroDefine.semanticAnalyze` reduces
|
|
8616
|
+
// the production (only the function-like alternative needs it, and
|
|
8617
|
+
// it knows that from its own children).
|
|
8618
|
+
if (token.type === Keyword.MACRO_DEFINE_PARAMS) {
|
|
8619
|
+
sematicAnalyzer.pushScope();
|
|
8620
|
+
for(var _iterator = _create_for_of_iterator_helper_loose(ParserUtils.parseMacroParamList(token.lexeme)), _step; !(_step = _iterator()).done;){
|
|
8621
|
+
var p = _step.value;
|
|
8622
|
+
sematicAnalyzer.symbolTableStack.insert(new SymbolInfo(p, ESymbolType.VAR));
|
|
8623
|
+
}
|
|
8624
|
+
}
|
|
8409
8625
|
nextToken = tokens.next();
|
|
8410
8626
|
} else if ((actionInfo == null ? void 0 : actionInfo.action) === EAction.Accept) {
|
|
8411
8627
|
sematicAnalyzer.acceptRule == null ? void 0 : sematicAnalyzer.acceptRule.call(sematicAnalyzer, sematicAnalyzer);
|
|
@@ -9366,7 +9582,7 @@ ShaderCompiler._shaderPositionPool = ShaderCompilerUtils.createObjectPool(Shader
|
|
|
9366
9582
|
ShaderCompiler._shaderRangePool = ShaderCompilerUtils.createObjectPool(ShaderRange);
|
|
9367
9583
|
|
|
9368
9584
|
//@ts-ignore
|
|
9369
|
-
var version = "2.0.0-alpha.
|
|
9585
|
+
var version = "2.0.0-alpha.33";
|
|
9370
9586
|
var mode = "Release";
|
|
9371
9587
|
mode = "Verbose";
|
|
9372
9588
|
console.log("Galacean Engine Shader Compiler Version: " + version + " | Mode: " + mode);
|