@tokens-studio/tokenscript-interpreter 0.36.3 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/dist/chunk-2EEKBDOX.js +5308 -0
  2. package/dist/chunk-2EEKBDOX.js.map +1 -0
  3. package/dist/chunk-2NMUBWBX.js +5861 -0
  4. package/dist/chunk-2NMUBWBX.js.map +1 -0
  5. package/dist/chunk-2OHE65GL.js +5779 -0
  6. package/dist/chunk-2OHE65GL.js.map +1 -0
  7. package/dist/chunk-2PZR6BQ6.js +5773 -0
  8. package/dist/chunk-2PZR6BQ6.js.map +1 -0
  9. package/dist/chunk-2QDDLPUW.js +5858 -0
  10. package/dist/chunk-2QDDLPUW.js.map +1 -0
  11. package/dist/chunk-4DUQBXYY.js +5762 -0
  12. package/dist/chunk-4DUQBXYY.js.map +1 -0
  13. package/dist/chunk-4SLJE4IW.js +5322 -0
  14. package/dist/chunk-4SLJE4IW.js.map +1 -0
  15. package/dist/chunk-6ABZOYUP.js +5802 -0
  16. package/dist/chunk-6ABZOYUP.js.map +1 -0
  17. package/dist/chunk-6HQZVWXZ.js +5341 -0
  18. package/dist/chunk-6HQZVWXZ.js.map +1 -0
  19. package/dist/chunk-6UY773C4.js +5292 -0
  20. package/dist/chunk-6UY773C4.js.map +1 -0
  21. package/dist/chunk-75Z55XEZ.js +5681 -0
  22. package/dist/chunk-75Z55XEZ.js.map +1 -0
  23. package/dist/chunk-7IWYKR22.js +5778 -0
  24. package/dist/chunk-7IWYKR22.js.map +1 -0
  25. package/dist/chunk-AVZUAMNS.js +5757 -0
  26. package/dist/chunk-AVZUAMNS.js.map +1 -0
  27. package/dist/chunk-BL7GZSRR.js +5724 -0
  28. package/dist/chunk-BL7GZSRR.js.map +1 -0
  29. package/dist/chunk-BMZ5NY7J.js +93 -0
  30. package/dist/chunk-BMZ5NY7J.js.map +1 -0
  31. package/dist/{chunk-AXH5N7KV.js → chunk-BNLQ6GCU.js} +2 -6
  32. package/dist/chunk-BNLQ6GCU.js.map +1 -0
  33. package/dist/chunk-BSJBGMCX.js +93 -0
  34. package/dist/{chunk-RI2BWY7D.js.map → chunk-BSJBGMCX.js.map} +1 -1
  35. package/dist/chunk-BUJRELXW.js +5342 -0
  36. package/dist/chunk-BUJRELXW.js.map +1 -0
  37. package/dist/chunk-DCOIGXSK.js +5763 -0
  38. package/dist/chunk-DCOIGXSK.js.map +1 -0
  39. package/dist/chunk-DZDZDYPO.js +5654 -0
  40. package/dist/chunk-DZDZDYPO.js.map +1 -0
  41. package/dist/{chunk-5S3H4SYX.js → chunk-GAE7SZLZ.js} +154 -9
  42. package/dist/chunk-GAE7SZLZ.js.map +1 -0
  43. package/dist/chunk-HFLLWRRV.js +5791 -0
  44. package/dist/chunk-HFLLWRRV.js.map +1 -0
  45. package/dist/{lib/chunk-ODVWXGOM.js → chunk-JL4UU4PY.js} +2 -8
  46. package/dist/chunk-JL4UU4PY.js.map +1 -0
  47. package/dist/{chunk-CKLFRLH7.js → chunk-JUGNHFDN.js} +220 -338
  48. package/dist/chunk-JUGNHFDN.js.map +1 -0
  49. package/dist/{chunk-RI2BWY7D.js → chunk-K2OUSWUX.js} +2 -3
  50. package/dist/chunk-K2OUSWUX.js.map +1 -0
  51. package/dist/chunk-KOLA6XR5.js +5770 -0
  52. package/dist/chunk-KOLA6XR5.js.map +1 -0
  53. package/dist/{chunk-3ZOUTFP5.js → chunk-L77CTMYP.js} +169 -296
  54. package/dist/chunk-L77CTMYP.js.map +1 -0
  55. package/dist/chunk-LIXBSHBJ.js +99 -0
  56. package/dist/chunk-LIXBSHBJ.js.map +1 -0
  57. package/dist/chunk-LM5SZQV5.js +5763 -0
  58. package/dist/chunk-LM5SZQV5.js.map +1 -0
  59. package/dist/chunk-M76AGXPG.js +5772 -0
  60. package/dist/chunk-M76AGXPG.js.map +1 -0
  61. package/dist/{chunk-QP7M6WUR.js → chunk-OV2GMYVM.js} +221 -341
  62. package/dist/chunk-OV2GMYVM.js.map +1 -0
  63. package/dist/{chunk-33CDF4L4.js → chunk-P4VLJQEI.js} +235 -838
  64. package/dist/chunk-P4VLJQEI.js.map +1 -0
  65. package/dist/chunk-QLSMLF5S.js +5302 -0
  66. package/dist/chunk-QLSMLF5S.js.map +1 -0
  67. package/dist/chunk-QYTZHMUN.js +5831 -0
  68. package/dist/chunk-QYTZHMUN.js.map +1 -0
  69. package/dist/chunk-SBM4WTQW.js +5771 -0
  70. package/dist/chunk-SBM4WTQW.js.map +1 -0
  71. package/dist/chunk-UAQCLV6Y.js +5816 -0
  72. package/dist/chunk-UAQCLV6Y.js.map +1 -0
  73. package/dist/chunk-YIZGWYGL.js +5300 -0
  74. package/dist/chunk-YIZGWYGL.js.map +1 -0
  75. package/dist/chunk-Z437BNC5.js +107 -0
  76. package/dist/chunk-Z437BNC5.js.map +1 -0
  77. package/dist/cli.js +182 -17
  78. package/dist/cli.js.map +1 -1
  79. package/dist/compliance-suite.js +3 -5
  80. package/dist/compliance-suite.js.map +1 -1
  81. package/dist/config-Bb9I9K-y.d.ts +1005 -0
  82. package/dist/config-Be-GTPYh.d.ts +976 -0
  83. package/dist/config-BkIqJNxv.d.ts +1009 -0
  84. package/dist/config-Cp5BqDfR.d.ts +731 -0
  85. package/dist/config-D36YRJGj.d.ts +1007 -0
  86. package/dist/{config-CFhN7-6U.d.ts → config-DB5rZBMx.d.ts} +109 -17
  87. package/dist/config-DQj8LHMT.d.ts +995 -0
  88. package/dist/{config-DtbN3iyg.d.ts → config-Mw_Iq324.d.ts} +5 -2
  89. package/dist/config-P6Ivo_zY.d.ts +997 -0
  90. package/dist/config-RCpZF46f.d.ts +960 -0
  91. package/dist/lib/{chunk-PXS4WZYB.cjs → chunk-EMRAAGPR.cjs} +102 -100
  92. package/dist/lib/chunk-EMRAAGPR.cjs.map +1 -0
  93. package/dist/lib/{chunk-XHA2RNU7.cjs → chunk-JQKYSUJJ.cjs} +728 -568
  94. package/dist/lib/chunk-JQKYSUJJ.cjs.map +1 -0
  95. package/dist/lib/{chunk-73YLAUUC.js → chunk-MD2DETZV.js} +5 -3
  96. package/dist/lib/chunk-MD2DETZV.js.map +1 -0
  97. package/dist/lib/chunk-SLITBMFB.js +114 -0
  98. package/dist/lib/chunk-SLITBMFB.js.map +1 -0
  99. package/dist/lib/{chunk-F5SBEZH2.js → chunk-VXZQQBEA.js} +175 -16
  100. package/dist/lib/chunk-VXZQQBEA.js.map +1 -0
  101. package/dist/lib/{chunk-LEYHQJTL.cjs → chunk-ZMMIYWFF.cjs} +11 -2
  102. package/dist/lib/chunk-ZMMIYWFF.cjs.map +1 -0
  103. package/dist/lib/index.cjs +99 -91
  104. package/dist/lib/index.d.cts +4 -4
  105. package/dist/lib/index.d.ts +4 -4
  106. package/dist/lib/index.js +3 -3
  107. package/dist/lib/{interpreter-6QwMkUqD.d.cts → interpreter-ByrEtz7T.d.ts} +54 -4
  108. package/dist/lib/{interpreter-v7WiwSP9.d.ts → interpreter-CG0Jw_k-.d.cts} +54 -4
  109. package/dist/lib/interpreter.cjs +81 -73
  110. package/dist/lib/interpreter.d.cts +7 -6
  111. package/dist/lib/interpreter.d.ts +7 -6
  112. package/dist/lib/interpreter.js +3 -3
  113. package/dist/lib/processor-node.cjs +12 -12
  114. package/dist/lib/processor-node.d.cts +3 -3
  115. package/dist/lib/processor-node.d.ts +3 -3
  116. package/dist/lib/processor-node.js +3 -3
  117. package/dist/lib/processor.cjs +17 -17
  118. package/dist/lib/processor.d.cts +4 -4
  119. package/dist/lib/processor.d.ts +4 -4
  120. package/dist/lib/processor.js +3 -3
  121. package/dist/lib/schema.cjs +5 -5
  122. package/dist/lib/schema.d.cts +1 -1
  123. package/dist/lib/schema.d.ts +1 -1
  124. package/dist/lib/schema.js +3 -3
  125. package/dist/lib/syntax-highlighting.cjs +15 -15
  126. package/dist/lib/syntax-highlighting.d.cts +1 -1
  127. package/dist/lib/syntax-highlighting.d.ts +1 -1
  128. package/dist/lib/syntax-highlighting.js +2 -2
  129. package/dist/lib/{types-BI0AZ4Ej.d.ts → types-BZAWM2oN.d.ts} +2 -2
  130. package/dist/lib/{types-cFwP43uv.d.cts → types-BhyJ6plH.d.cts} +2 -2
  131. package/dist/lib/{types-EB8V9c46.d.cts → types-DA9_CC7p.d.cts} +5 -2
  132. package/dist/lib/{types-EB8V9c46.d.ts → types-DA9_CC7p.d.ts} +5 -2
  133. package/dist/lib/types.cjs +10 -6
  134. package/dist/lib/types.d.cts +1 -1
  135. package/dist/lib/types.d.ts +1 -1
  136. package/dist/lib/types.js +1 -1
  137. package/dist/processor/index.d.ts +1 -1
  138. package/dist/processor/index.js +18 -2
  139. package/dist/processor/index.js.map +1 -1
  140. package/dist/repl.d.ts +15 -3
  141. package/dist/repl.js +6 -8
  142. package/dist/repl.js.map +1 -1
  143. package/dist/token-schemas.js +414 -0
  144. package/dist/types.d.ts +1 -1
  145. package/dist/types.js +1 -1
  146. package/package.json +1 -1
  147. package/dist/chunk-33CDF4L4.js.map +0 -1
  148. package/dist/chunk-3ZOUTFP5.js.map +0 -1
  149. package/dist/chunk-5S3H4SYX.js.map +0 -1
  150. package/dist/chunk-AXH5N7KV.js.map +0 -1
  151. package/dist/chunk-CKLFRLH7.js.map +0 -1
  152. package/dist/chunk-GJIOYGP6.js +0 -6446
  153. package/dist/chunk-GJIOYGP6.js.map +0 -1
  154. package/dist/chunk-HHCPY4WI.js +0 -6456
  155. package/dist/chunk-HHCPY4WI.js.map +0 -1
  156. package/dist/chunk-MXKGYBE4.js +0 -6457
  157. package/dist/chunk-MXKGYBE4.js.map +0 -1
  158. package/dist/chunk-NGG6MBER.js +0 -6452
  159. package/dist/chunk-NGG6MBER.js.map +0 -1
  160. package/dist/chunk-QP7M6WUR.js.map +0 -1
  161. package/dist/lib/chunk-73YLAUUC.js.map +0 -1
  162. package/dist/lib/chunk-F5SBEZH2.js.map +0 -1
  163. package/dist/lib/chunk-LEYHQJTL.cjs.map +0 -1
  164. package/dist/lib/chunk-ODVWXGOM.js.map +0 -1
  165. package/dist/lib/chunk-PXS4WZYB.cjs.map +0 -1
  166. package/dist/lib/chunk-XHA2RNU7.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
- import { SupportedFormats, ReservedKeyword, UNINTERPRETED_KEYWORDS } from './chunk-AXH5N7KV.js';
2
- import { Color, Fn, Unit, Token, ZodError } from '@tokens-studio/schema-validation';
1
+ import { SupportedFormats, ReservedKeyword, UNINTERPRETED_KEYWORDS } from './chunk-BNLQ6GCU.js';
2
+ import { type } from 'arktype';
3
3
 
4
4
  // src/interpreter/errors/messages/en.ts
5
5
  var messages = {
@@ -17,7 +17,6 @@ var messages = {
17
17
  ["PARSER_CONDITION_MUST_BE_BOOLEAN" /* CONDITION_MUST_BE_BOOLEAN */]: "If/elif condition must be a boolean",
18
18
  ["PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */]: (data) => data?.message ? String(data.message) : "Invalid syntax",
19
19
  ["PARSER_UNEXPECTED_END" /* UNEXPECTED_END */]: "Unexpected end of input",
20
- ["PARSER_TOLERANT_REQUIRES_INLINE" /* TOLERANT_REQUIRES_INLINE */]: "Tolerant mode only supports inline expressions. Use parse(true) for tolerant parsing.",
21
20
  // Interpreter errors
22
21
  ["INT_UNKNOWN_NODE_TYPE" /* UNKNOWN_NODE_TYPE */]: (data) => `No visit method for AST node type: ${data.nodeType}`,
23
22
  ["INT_ARITHMETIC_REQUIRES_NUMBER" /* ARITHMETIC_REQUIRES_NUMBER */]: (data) => `Arithmetic operator ${data.operator} requires Number or NumberWithUnit operands, got ${data.leftType} and ${data.rightType}.`,
@@ -44,9 +43,6 @@ var messages = {
44
43
  ["INT_MAX_ITERATIONS_EXCEEDED" /* MAX_ITERATIONS_EXCEEDED */]: "Max iterations exceeded in while loop.",
45
44
  ["INT_WHILE_CONDITION_NOT_BOOLEAN" /* WHILE_CONDITION_NOT_BOOLEAN */]: "While loop condition must be a boolean.",
46
45
  ["INT_IF_CONDITION_NOT_BOOLEAN" /* IF_CONDITION_NOT_BOOLEAN */]: "If/elif condition must be a boolean.",
47
- ["INT_FOR_EACH_NOT_LIST" /* FOR_EACH_NOT_LIST */]: (data) => `for...in requires a List, got ${data.actualType}.`,
48
- ["INT_FOR_EACH_VARIABLE_SHADOW" /* FOR_EACH_VARIABLE_SHADOW */]: (data) => `for...in variable '${data.name}' shadows an existing variable in this scope.`,
49
- ["INT_FOR_EACH_DUPLICATE_VARS" /* FOR_EACH_DUPLICATE_VARS */]: (data) => `for...in item and index variables must have different names, both are '${data.name}'.`,
50
46
  ["INT_UNKNOWN_ERROR" /* UNKNOWN_ERROR */]: "An unknown error occurred during interpretation.",
51
47
  // Operations errors
52
48
  ["OP_UNSUPPORTED_OPERAND_TYPE" /* UNSUPPORTED_OPERAND_TYPE */]: (data) => `Unsupported operand type for unit decomposition: ${data.type}`,
@@ -1830,59 +1826,6 @@ function stringifyInterpreterResult(value) {
1830
1826
  return String(value);
1831
1827
  }
1832
1828
 
1833
- // src/interpreter/tolerant/partial-nodes.ts
1834
- var PartialReferenceNode = class {
1835
- constructor(partialValue, token) {
1836
- this.partialValue = partialValue;
1837
- this.token = token;
1838
- this.nodeType = "PartialReferenceNode";
1839
- }
1840
- };
1841
- var PartialStringNode = class {
1842
- constructor(partialValue, quoteType, token) {
1843
- this.partialValue = partialValue;
1844
- this.quoteType = quoteType;
1845
- this.token = token;
1846
- this.nodeType = "PartialStringNode";
1847
- }
1848
- };
1849
- var PartialFunctionCallNode = class {
1850
- constructor(name, args, token) {
1851
- this.name = name;
1852
- this.args = args;
1853
- this.token = token;
1854
- this.nodeType = "PartialFunctionCallNode";
1855
- }
1856
- };
1857
- var PartialBinOpNode = class {
1858
- constructor(left, opToken) {
1859
- this.left = left;
1860
- this.opToken = opToken;
1861
- this.nodeType = "PartialBinOpNode";
1862
- this.token = opToken;
1863
- }
1864
- get op() {
1865
- return this.opToken.value;
1866
- }
1867
- };
1868
- var PartialUnaryOpNode = class {
1869
- constructor(opToken) {
1870
- this.opToken = opToken;
1871
- this.nodeType = "PartialUnaryOpNode";
1872
- this.token = opToken;
1873
- }
1874
- get op() {
1875
- return this.opToken.value;
1876
- }
1877
- };
1878
- var PartialParenNode = class {
1879
- constructor(expr, token) {
1880
- this.expr = expr;
1881
- this.token = token;
1882
- this.nodeType = "PartialParenNode";
1883
- }
1884
- };
1885
-
1886
1829
  // src/interpreter/ast.ts
1887
1830
  var BinOpNode = class {
1888
1831
  constructor(left, opToken, right, token) {
@@ -1915,13 +1858,6 @@ var StringNode = class {
1915
1858
  this.value = token.value;
1916
1859
  }
1917
1860
  };
1918
- var TemplateStringNode = class {
1919
- constructor(parts, token) {
1920
- this.parts = parts;
1921
- this.token = token;
1922
- this.nodeType = "TemplateStringNode";
1923
- }
1924
- };
1925
1861
  var UnaryOpNode = class {
1926
1862
  constructor(opToken, expr, token) {
1927
1863
  this.opToken = opToken;
@@ -2071,16 +2007,6 @@ var WhileNode = class {
2071
2007
  this.nodeType = "WhileNode";
2072
2008
  }
2073
2009
  };
2074
- var ForEachNode = class {
2075
- constructor(itemVar, indexVar, collection, body, token) {
2076
- this.itemVar = itemVar;
2077
- this.indexVar = indexVar;
2078
- this.collection = collection;
2079
- this.body = body;
2080
- this.token = token;
2081
- this.nodeType = "ForEachNode";
2082
- }
2083
- };
2084
2010
  var IfConditionNode = class {
2085
2011
  constructor(condition, body, token) {
2086
2012
  this.condition = condition;
@@ -2114,7 +2040,6 @@ var StatementListNode = class {
2114
2040
  };
2115
2041
  var AttributeAccessNode = class {
2116
2042
  // 'left' is the object, 'right' is the attribute (IdentifierNode) or method (FunctionCallNode)
2117
- // In tolerant mode, 'right' may also be a PartialFunctionCallNode
2118
2043
  constructor(left, right, token) {
2119
2044
  this.left = left;
2120
2045
  this.right = right;
@@ -2150,9 +2075,6 @@ function walkAST(node, onVisit) {
2150
2075
  } else if (node instanceof WhileNode) {
2151
2076
  walkAST(node.condition, onVisit);
2152
2077
  walkAST(node.body, onVisit);
2153
- } else if (node instanceof ForEachNode) {
2154
- walkAST(node.collection, onVisit);
2155
- walkAST(node.body, onVisit);
2156
2078
  } else if (node instanceof IfConditionNode) {
2157
2079
  walkAST(node.condition, onVisit);
2158
2080
  walkAST(node.body, onVisit);
@@ -2169,23 +2091,11 @@ function walkAST(node, onVisit) {
2169
2091
  for (const statement of node.statements) {
2170
2092
  walkAST(statement, onVisit);
2171
2093
  }
2172
- } else if (node instanceof TemplateStringNode) {
2173
- for (const part of node.parts) {
2174
- walkAST(part, onVisit);
2175
- }
2176
2094
  } else if (node instanceof AttributeAccessNode) {
2177
2095
  walkAST(node.left, onVisit);
2178
- if (node.right instanceof FunctionCallNode || node.right instanceof PartialFunctionCallNode) {
2096
+ if (node.right instanceof FunctionCallNode) {
2179
2097
  walkAST(node.right, onVisit);
2180
2098
  }
2181
- } else if (node instanceof PartialBinOpNode) {
2182
- walkAST(node.left, onVisit);
2183
- } else if (node instanceof PartialUnaryOpNode) ; else if (node instanceof PartialFunctionCallNode) {
2184
- for (const arg of node.args) {
2185
- walkAST(arg, onVisit);
2186
- }
2187
- } else if (node instanceof PartialParenNode) {
2188
- walkAST(node.expr, onVisit);
2189
2099
  }
2190
2100
  }
2191
2101
  function filterAST(ast, predicate) {
@@ -2245,7 +2155,7 @@ for (const val of Object.values(ReservedKeyword)) {
2245
2155
  RESERVED_KEYWORD_STRINGS[val.toLowerCase()] = val;
2246
2156
  }
2247
2157
  var Lexer = class {
2248
- constructor(text, options) {
2158
+ constructor(text) {
2249
2159
  this.pos = 0;
2250
2160
  this.line = 1;
2251
2161
  this.column = 1;
@@ -2258,10 +2168,8 @@ var Lexer = class {
2258
2168
  * @see docs/tokenscript/edge-cases/format-unit-parsing.md
2259
2169
  */
2260
2170
  this._lastUnitableToken = null;
2261
- this.collectedTokens = [];
2262
2171
  this.text = text;
2263
- this.currentChar = this.pos < this.text.length ? this.text[this.pos] : null;
2264
- this.tolerant = options?.tolerant ?? false;
2172
+ this.currentChar = this.text[this.pos];
2265
2173
  }
2266
2174
  /**
2267
2175
  * Check if a FORMAT token (unit suffix) is valid at the given position.
@@ -2297,7 +2205,7 @@ var Lexer = class {
2297
2205
  }
2298
2206
  }
2299
2207
  peek(n = 1) {
2300
- return this.text[this.pos + n] ?? null;
2208
+ return this.text[this.pos + n];
2301
2209
  }
2302
2210
  skipWhitespace() {
2303
2211
  while (isSpace(this.currentChar)) {
@@ -2405,9 +2313,6 @@ var Lexer = class {
2405
2313
  let result = "";
2406
2314
  while (this.currentChar !== null && this.currentChar !== "}") {
2407
2315
  if (this.currentChar === "{") {
2408
- if (this.tolerant) {
2409
- break;
2410
- }
2411
2316
  this.error("LEXER_UNTERMINATED_REFERENCE" /* UNTERMINATED_REFERENCE */, {});
2412
2317
  }
2413
2318
  if (isSpace(this.currentChar)) {
@@ -2418,27 +2323,9 @@ var Lexer = class {
2418
2323
  this.advance();
2419
2324
  }
2420
2325
  if (this.currentChar === null) {
2421
- if (this.tolerant) {
2422
- return {
2423
- type: "PARTIAL_REFERENCE" /* PARTIAL_REFERENCE */,
2424
- value: result,
2425
- line: this.line,
2426
- pos: refStartPos,
2427
- endPos: this.pos
2428
- };
2429
- }
2430
2326
  this.error("LEXER_UNTERMINATED_REFERENCE" /* UNTERMINATED_REFERENCE */, {});
2431
2327
  }
2432
2328
  if (result === "") {
2433
- if (this.tolerant) {
2434
- return {
2435
- type: "PARTIAL_REFERENCE" /* PARTIAL_REFERENCE */,
2436
- value: "",
2437
- line: this.line,
2438
- pos: refStartPos,
2439
- endPos: this.pos
2440
- };
2441
- }
2442
2329
  this.error("LEXER_EMPTY_VARIABLE_NAME" /* EMPTY_VARIABLE_NAME */, {});
2443
2330
  }
2444
2331
  const refEndPos = this.pos;
@@ -2462,15 +2349,6 @@ var Lexer = class {
2462
2349
  this.advance();
2463
2350
  }
2464
2351
  if (this.currentChar === null) {
2465
- if (this.tolerant) {
2466
- return {
2467
- type: "PARTIAL_STRING" /* PARTIAL_STRING */,
2468
- value: result,
2469
- line: this.line,
2470
- pos: startPos,
2471
- endPos: this.pos
2472
- };
2473
- }
2474
2352
  this.error("LEXER_UNTERMINATED_STRING" /* UNTERMINATED_STRING */, { quoteType });
2475
2353
  }
2476
2354
  this.eat(quoteType);
@@ -2482,51 +2360,6 @@ var Lexer = class {
2482
2360
  endPos: this.pos
2483
2361
  };
2484
2362
  }
2485
- /**
2486
- * Read a backtick-delimited template string.
2487
- * Supports escape sequences: \{ \$ \` \\
2488
- * The raw content (with escapes preserved) is stored as the token value.
2489
- * The parser handles splitting into segments.
2490
- */
2491
- templateString() {
2492
- const startPos = this.pos;
2493
- this.eat("`");
2494
- let result = "";
2495
- while (this.currentChar !== null && this.currentChar !== "`") {
2496
- if (this.currentChar === "\\") {
2497
- const next = this.peek();
2498
- if (next === "{" || next === "$" || next === "`" || next === "\\") {
2499
- result += "\\";
2500
- result += next;
2501
- this.advance();
2502
- this.advance();
2503
- continue;
2504
- }
2505
- }
2506
- result += this.currentChar;
2507
- this.advance();
2508
- }
2509
- if (this.currentChar === null) {
2510
- if (this.tolerant) {
2511
- return {
2512
- type: "TEMPLATE_STRING" /* TEMPLATE_STRING */,
2513
- value: result,
2514
- line: this.line,
2515
- pos: startPos,
2516
- endPos: this.pos
2517
- };
2518
- }
2519
- this.error("LEXER_UNTERMINATED_TEMPLATE_STRING" /* UNTERMINATED_TEMPLATE_STRING */, {});
2520
- }
2521
- this.eat("`");
2522
- return {
2523
- type: "TEMPLATE_STRING" /* TEMPLATE_STRING */,
2524
- value: result,
2525
- line: this.line,
2526
- pos: startPos,
2527
- endPos: this.pos
2528
- };
2529
- }
2530
2363
  hexColor() {
2531
2364
  const startPos = this.pos;
2532
2365
  let result = "";
@@ -2535,15 +2368,6 @@ var Lexer = class {
2535
2368
  this.advance();
2536
2369
  }
2537
2370
  if (result.length !== 4 && result.length !== 5 && result.length !== 7 && result.length !== 9) {
2538
- if (this.tolerant) {
2539
- return {
2540
- type: "HEX_COLOR" /* HEX_COLOR */,
2541
- value: result,
2542
- line: this.line,
2543
- pos: startPos,
2544
- endPos: this.pos
2545
- };
2546
- }
2547
2371
  this.error("LEXER_INVALID_HEX_COLOR_FORMAT" /* INVALID_HEX_COLOR_FORMAT */, {
2548
2372
  value: result,
2549
2373
  expectedLength: "#RGB, #RGBA, #RRGGBB, or #RRGGBBAA"
@@ -2557,12 +2381,6 @@ var Lexer = class {
2557
2381
  endPos: this.pos
2558
2382
  };
2559
2383
  }
2560
- collectToken(token) {
2561
- if (this.tolerant) {
2562
- this.collectedTokens.push(token);
2563
- }
2564
- return token;
2565
- }
2566
2384
  nextToken() {
2567
2385
  while (this.currentChar !== null) {
2568
2386
  this.skipWhitespace();
@@ -2572,130 +2390,127 @@ var Lexer = class {
2572
2390
  continue;
2573
2391
  }
2574
2392
  if (this.isDigit()) {
2575
- return this.collectToken(this.number());
2393
+ return this.number();
2576
2394
  }
2577
2395
  if (this.currentChar === "'" || this.currentChar === '"') {
2578
- return this.collectToken(this.explicitString(this.currentChar));
2579
- }
2580
- if (this.currentChar === "`") {
2581
- return this.collectToken(this.templateString());
2396
+ return this.explicitString(this.currentChar);
2582
2397
  }
2583
2398
  if (this.isValidIdentifierStart(this.currentChar)) {
2584
- return this.collectToken(this.stringElement());
2399
+ return this.stringElement();
2585
2400
  }
2586
2401
  if (this.currentChar === "{") {
2587
- return this.collectToken(this.reference());
2402
+ return this.reference();
2588
2403
  }
2589
2404
  if (this.currentChar === "[") {
2590
2405
  const startPos = this.pos;
2591
2406
  this.eat("[");
2592
- return this.collectToken({
2407
+ return {
2593
2408
  type: "LBLOCK" /* LBLOCK */,
2594
2409
  value: "[",
2595
2410
  line: this.line,
2596
2411
  pos: startPos,
2597
2412
  endPos: this.pos
2598
- });
2413
+ };
2599
2414
  }
2600
2415
  if (this.currentChar === "]") {
2601
2416
  const startPos = this.pos;
2602
2417
  this.eat("]");
2603
- return this.collectToken({
2418
+ return {
2604
2419
  type: "RBLOCK" /* RBLOCK */,
2605
2420
  value: "]",
2606
2421
  line: this.line,
2607
2422
  pos: startPos,
2608
2423
  endPos: this.pos
2609
- });
2424
+ };
2610
2425
  }
2611
2426
  if (this.currentChar === "!" && this.peek() === "=") {
2612
2427
  const startPos = this.pos;
2613
2428
  this.eat("!");
2614
2429
  this.eat("=");
2615
- return this.collectToken({
2430
+ return {
2616
2431
  type: "IS_NOT_EQ" /* IS_NOT_EQ */,
2617
2432
  value: "!=",
2618
2433
  line: this.line,
2619
2434
  pos: startPos,
2620
2435
  endPos: this.pos
2621
- });
2436
+ };
2622
2437
  }
2623
2438
  if (this.currentChar === "+") {
2624
2439
  const startPos = this.pos;
2625
2440
  this.eat("+");
2626
- return this.collectToken({
2441
+ return {
2627
2442
  type: "OPERATION" /* OPERATION */,
2628
2443
  value: "+" /* ADD */,
2629
2444
  line: this.line,
2630
2445
  pos: startPos,
2631
2446
  endPos: this.pos
2632
- });
2447
+ };
2633
2448
  }
2634
2449
  if (this.currentChar === "-") {
2635
2450
  const startPos = this.pos;
2636
2451
  this.eat("-");
2637
- return this.collectToken({
2452
+ return {
2638
2453
  type: "OPERATION" /* OPERATION */,
2639
2454
  value: "-" /* SUBTRACT */,
2640
2455
  line: this.line,
2641
2456
  pos: startPos,
2642
2457
  endPos: this.pos
2643
- });
2458
+ };
2644
2459
  }
2645
2460
  if (this.currentChar === "*") {
2646
2461
  const startPos = this.pos;
2647
2462
  this.eat("*");
2648
- return this.collectToken({
2463
+ return {
2649
2464
  type: "OPERATION" /* OPERATION */,
2650
2465
  value: "*" /* MULTIPLY */,
2651
2466
  line: this.line,
2652
2467
  pos: startPos,
2653
2468
  endPos: this.pos
2654
- });
2469
+ };
2655
2470
  }
2656
2471
  if (this.currentChar === "/") {
2657
2472
  const startPos = this.pos;
2658
2473
  this.eat("/");
2659
- return this.collectToken({
2474
+ return {
2660
2475
  type: "OPERATION" /* OPERATION */,
2661
2476
  value: "/" /* DIVIDE */,
2662
2477
  line: this.line,
2663
2478
  pos: startPos,
2664
2479
  endPos: this.pos
2665
- });
2480
+ };
2666
2481
  }
2667
2482
  if (this.currentChar === "^") {
2668
2483
  const startPos = this.pos;
2669
2484
  this.eat("^");
2670
- return this.collectToken({
2485
+ return {
2671
2486
  type: "OPERATION" /* OPERATION */,
2672
2487
  value: "^" /* POWER */,
2673
2488
  line: this.line,
2674
2489
  pos: startPos,
2675
2490
  endPos: this.pos
2676
- });
2491
+ };
2677
2492
  }
2678
2493
  if (this.currentChar === "!") {
2679
2494
  const startPos = this.pos;
2680
2495
  this.eat("!");
2681
- return this.collectToken({
2496
+ return {
2682
2497
  type: "OPERATION" /* OPERATION */,
2683
2498
  value: "!" /* LOGIC_NOT */,
2684
2499
  line: this.line,
2685
2500
  pos: startPos,
2686
2501
  endPos: this.pos
2687
- });
2502
+ };
2688
2503
  }
2689
2504
  if (this.currentChar === "(") {
2690
2505
  const startPos = this.pos;
2691
2506
  this.eat("(");
2692
- return this.collectToken({
2507
+ return {
2693
2508
  type: "LPAREN" /* LPAREN */,
2694
2509
  value: "(",
2695
2510
  line: this.line,
2696
2511
  pos: startPos,
2697
2512
  endPos: this.pos
2698
- });
2513
+ };
2699
2514
  }
2700
2515
  if (this.currentChar === ")") {
2701
2516
  const startPos = this.pos;
@@ -2708,162 +2523,158 @@ var Lexer = class {
2708
2523
  endPos: this.pos
2709
2524
  };
2710
2525
  this._lastUnitableToken = token;
2711
- return this.collectToken(token);
2526
+ return token;
2712
2527
  }
2713
2528
  if (this.currentChar === ",") {
2714
2529
  const startPos = this.pos;
2715
2530
  this.eat(",");
2716
- return this.collectToken({
2531
+ return {
2717
2532
  type: "COMMA" /* COMMA */,
2718
2533
  value: ",",
2719
2534
  line: this.line,
2720
2535
  pos: startPos,
2721
2536
  endPos: this.pos
2722
- });
2537
+ };
2723
2538
  }
2724
2539
  if (this.currentChar === ".") {
2725
2540
  if (this.peek() !== null && isNumber2(this.peek())) {
2726
- return this.collectToken(this.number());
2541
+ return this.number();
2727
2542
  }
2728
2543
  const startPos = this.pos;
2729
2544
  this.eat(".");
2730
- return this.collectToken({
2545
+ return {
2731
2546
  type: "DOT" /* DOT */,
2732
2547
  value: ".",
2733
2548
  line: this.line,
2734
2549
  pos: startPos,
2735
2550
  endPos: this.pos
2736
- });
2551
+ };
2737
2552
  }
2738
2553
  if (this.currentChar === "#") {
2739
- return this.collectToken(this.hexColor());
2554
+ return this.hexColor();
2740
2555
  }
2741
2556
  if (this.currentChar === "%") {
2742
2557
  const startPos = this.pos;
2743
2558
  this.eat("%");
2744
- return this.collectToken({
2559
+ return {
2745
2560
  type: "FORMAT" /* FORMAT */,
2746
2561
  value: "%" /* PERCENTAGE */,
2747
2562
  line: this.line,
2748
2563
  pos: startPos,
2749
2564
  endPos: this.pos
2750
- });
2565
+ };
2751
2566
  }
2752
2567
  if (this.currentChar === "=") {
2753
2568
  const startPos = this.pos;
2754
2569
  if (this.peek() === "=") {
2755
2570
  this.eat("=");
2756
2571
  this.eat("=");
2757
- return this.collectToken({
2572
+ return {
2758
2573
  type: "IS_EQ" /* IS_EQ */,
2759
2574
  value: "==",
2760
2575
  line: this.line,
2761
2576
  pos: startPos,
2762
2577
  endPos: this.pos
2763
- });
2578
+ };
2764
2579
  }
2765
2580
  this.eat("=");
2766
- return this.collectToken({
2581
+ return {
2767
2582
  type: "ASSIGN" /* ASSIGN */,
2768
2583
  value: "=",
2769
2584
  line: this.line,
2770
2585
  pos: startPos,
2771
2586
  endPos: this.pos
2772
- });
2587
+ };
2773
2588
  }
2774
2589
  if (this.currentChar === ">") {
2775
2590
  const startPos = this.pos;
2776
2591
  if (this.peek() === "=") {
2777
2592
  this.eat(">");
2778
2593
  this.eat("=");
2779
- return this.collectToken({
2594
+ return {
2780
2595
  type: "IS_GT_EQ" /* IS_GT_EQ */,
2781
2596
  value: ">=",
2782
2597
  line: this.line,
2783
2598
  pos: startPos,
2784
2599
  endPos: this.pos
2785
- });
2600
+ };
2786
2601
  }
2787
2602
  this.eat(">");
2788
- return this.collectToken({
2603
+ return {
2789
2604
  type: "GT" /* IS_GT */,
2790
2605
  value: ">",
2791
2606
  line: this.line,
2792
2607
  pos: startPos,
2793
2608
  endPos: this.pos
2794
- });
2609
+ };
2795
2610
  }
2796
2611
  if (this.currentChar === "<") {
2797
2612
  const startPos = this.pos;
2798
2613
  if (this.peek() === "=") {
2799
2614
  this.eat("<");
2800
2615
  this.eat("=");
2801
- return this.collectToken({
2616
+ return {
2802
2617
  type: "IS_LT_EQ" /* IS_LT_EQ */,
2803
2618
  value: "<=",
2804
2619
  line: this.line,
2805
2620
  pos: startPos,
2806
2621
  endPos: this.pos
2807
- });
2622
+ };
2808
2623
  }
2809
2624
  this.eat("<");
2810
- return this.collectToken({
2625
+ return {
2811
2626
  type: "LT" /* IS_LT */,
2812
2627
  value: "<",
2813
2628
  line: this.line,
2814
2629
  pos: startPos,
2815
2630
  endPos: this.pos
2816
- });
2631
+ };
2817
2632
  }
2818
2633
  if (this.currentChar === ";") {
2819
2634
  const startPos = this.pos;
2820
2635
  this.eat(";");
2821
- return this.collectToken({
2636
+ return {
2822
2637
  type: "SEMICOLON" /* SEMICOLON */,
2823
2638
  value: ";",
2824
2639
  line: this.line,
2825
2640
  pos: startPos,
2826
2641
  endPos: this.pos
2827
- });
2642
+ };
2828
2643
  }
2829
2644
  if (this.currentChar === "&" && this.peek() === "&") {
2830
2645
  const startPos = this.pos;
2831
2646
  this.eat("&");
2832
2647
  this.eat("&");
2833
- return this.collectToken({
2648
+ return {
2834
2649
  type: "LOGIC_AND" /* LOGIC_AND */,
2835
2650
  value: "&&" /* LOGIC_AND */,
2836
2651
  line: this.line,
2837
2652
  pos: startPos,
2838
2653
  endPos: this.pos
2839
- });
2654
+ };
2840
2655
  }
2841
2656
  if (this.currentChar === "|" && this.peek() === "|") {
2842
2657
  const startPos = this.pos;
2843
2658
  this.eat("|");
2844
2659
  this.eat("|");
2845
- return this.collectToken({
2660
+ return {
2846
2661
  type: "LOGIC_OR" /* LOGIC_OR */,
2847
2662
  value: "||" /* LOGIC_OR */,
2848
2663
  line: this.line,
2849
2664
  pos: startPos,
2850
2665
  endPos: this.pos
2851
- });
2666
+ };
2852
2667
  }
2853
2668
  if (this.currentChar === ":") {
2854
2669
  const startPos = this.pos;
2855
2670
  this.eat(":");
2856
- return this.collectToken({
2671
+ return {
2857
2672
  type: "COLON" /* COLON */,
2858
2673
  value: ":",
2859
2674
  line: this.line,
2860
2675
  pos: startPos,
2861
2676
  endPos: this.pos
2862
- });
2863
- }
2864
- if (this.tolerant) {
2865
- this.advance();
2866
- continue;
2677
+ };
2867
2678
  }
2868
2679
  const char = this.currentChar === null ? "end of input" : this.currentChar;
2869
2680
  this.error("LEXER_INVALID_CHARACTER" /* INVALID_CHARACTER */, {
@@ -2871,48 +2682,18 @@ var Lexer = class {
2871
2682
  position: this.pos
2872
2683
  });
2873
2684
  }
2874
- const eofToken = {
2875
- type: "EOF" /* EOF */,
2876
- value: null,
2877
- line: this.line,
2878
- pos: this.pos,
2879
- endPos: this.pos
2880
- };
2881
- return this.collectToken(eofToken);
2882
- }
2883
- /**
2884
- * Get all tokens that have been collected during tokenization.
2885
- * This is useful for tolerant parsing to get all tokens including partial ones.
2886
- */
2887
- getAllTokens() {
2888
- return [...this.collectedTokens];
2889
- }
2890
- /**
2891
- * Tokenize the entire input and return all tokens.
2892
- * This is a convenience method for tolerant parsing.
2893
- */
2894
- tokenizeAll() {
2895
- const tokens = [];
2896
- let token = this.nextToken();
2897
- while (token.type !== "EOF" /* EOF */) {
2898
- tokens.push(token);
2899
- token = this.nextToken();
2900
- }
2901
- tokens.push(token);
2902
- return tokens;
2685
+ return { type: "EOF" /* EOF */, value: null, line: this.line, pos: this.pos, endPos: this.pos };
2903
2686
  }
2904
2687
  peekToken() {
2905
2688
  const savedPos = this.pos;
2906
2689
  const savedChar = this.currentChar;
2907
2690
  const savedLine = this.line;
2908
2691
  const savedColumn = this.column;
2909
- const savedCollectedLength = this.collectedTokens.length;
2910
2692
  const nextToken = this.nextToken();
2911
2693
  this.pos = savedPos;
2912
2694
  this.currentChar = savedChar;
2913
2695
  this.line = savedLine;
2914
2696
  this.column = savedColumn;
2915
- this.collectedTokens.length = savedCollectedLength;
2916
2697
  return nextToken.type === "EOF" /* EOF */ ? null : nextToken;
2917
2698
  }
2918
2699
  peekTokens(n) {
@@ -2920,7 +2701,6 @@ var Lexer = class {
2920
2701
  const savedChar = this.currentChar;
2921
2702
  const savedLine = this.line;
2922
2703
  const savedColumn = this.column;
2923
- const savedCollectedLength = this.collectedTokens.length;
2924
2704
  const tokens = [];
2925
2705
  for (let i = 0; i < n; i++) {
2926
2706
  const token = this.nextToken();
@@ -2933,7 +2713,6 @@ var Lexer = class {
2933
2713
  this.currentChar = savedChar;
2934
2714
  this.line = savedLine;
2935
2715
  this.column = savedColumn;
2936
- this.collectedTokens.length = savedCollectedLength;
2937
2716
  return tokens.length > 0 ? tokens : null;
2938
2717
  }
2939
2718
  isEOF() {
@@ -2956,41 +2735,11 @@ var Lexer = class {
2956
2735
  };
2957
2736
 
2958
2737
  // src/interpreter/parser.ts
2959
- var Parser = class _Parser {
2960
- constructor(lexer, options) {
2738
+ var Parser = class {
2739
+ constructor(lexer) {
2961
2740
  this.requiredReferences = /* @__PURE__ */ new Set();
2962
- this.incompleteInfo = [];
2963
2741
  this.lexer = lexer;
2964
2742
  this.currentToken = this.lexer.nextToken();
2965
- this.tolerant = options?.tolerant ?? false;
2966
- }
2967
- /**
2968
- * In tolerant mode, check if the current token is EOF after consuming an operator.
2969
- * If so, record the incomplete info and return a PartialBinOpNode.
2970
- * Returns null if not at EOF or not in tolerant mode.
2971
- */
2972
- tryRecoverMissingOperand(left, opToken) {
2973
- if (this.tolerant && this.currentToken.type === "EOF" /* EOF */) {
2974
- this.incompleteInfo.push({
2975
- type: "missing_operand" /* MISSING_OPERAND */,
2976
- startPos: opToken.pos,
2977
- endPos: opToken.endPos
2978
- });
2979
- return new PartialBinOpNode(left, opToken);
2980
- }
2981
- return null;
2982
- }
2983
- /**
2984
- * Check if the parser encountered any incomplete constructs
2985
- */
2986
- hasIncomplete() {
2987
- return this.incompleteInfo.length > 0;
2988
- }
2989
- /**
2990
- * Get information about incomplete constructs
2991
- */
2992
- getIncomplete() {
2993
- return [...this.incompleteInfo];
2994
2743
  }
2995
2744
  formatError(message, token = this.currentToken) {
2996
2745
  const {
@@ -3114,8 +2863,6 @@ ${contextText}`;
3114
2863
  return this.returnStatement();
3115
2864
  case "while" /* WHILE */:
3116
2865
  return this.whileStatement();
3117
- case "for" /* FOR */:
3118
- return this.forStatement();
3119
2866
  case "if" /* IF */:
3120
2867
  return this.ifStatement();
3121
2868
  case "variable" /* VARIABLE */:
@@ -3171,18 +2918,7 @@ ${contextText}`;
3171
2918
  return new ReassignNode(name, assignmentExpr, varNameToken);
3172
2919
  }
3173
2920
  reference() {
3174
- const token = this.currentToken;
3175
- if (token.type === "PARTIAL_REFERENCE" /* PARTIAL_REFERENCE */) {
3176
- this.eat("PARTIAL_REFERENCE" /* PARTIAL_REFERENCE */);
3177
- this.incompleteInfo.push({
3178
- type: "unclosed_reference" /* UNCLOSED_REFERENCE */,
3179
- startPos: token.pos,
3180
- endPos: token.endPos,
3181
- partialValue: token.value
3182
- });
3183
- return new PartialReferenceNode(token.value, token);
3184
- }
3185
- const node = new ReferenceNode(token);
2921
+ const node = new ReferenceNode(this.currentToken);
3186
2922
  this.eat("REFERENCE" /* REFERENCE */);
3187
2923
  this.requiredReferences.add(node.value);
3188
2924
  if (this.currentToken.type === "FORMAT" /* FORMAT */) {
@@ -3195,8 +2931,6 @@ ${contextText}`;
3195
2931
  let node = this.logicTerm();
3196
2932
  while (this.currentToken.type === "LOGIC_AND" /* LOGIC_AND */ || this.currentToken.type === "LOGIC_OR" /* LOGIC_OR */) {
3197
2933
  const token = this.eat(this.currentToken.type);
3198
- const partial = this.tryRecoverMissingOperand(node, token);
3199
- if (partial) return partial;
3200
2934
  node = new BinOpNode(node, token, this.logicTerm());
3201
2935
  }
3202
2936
  return node;
@@ -3225,48 +2959,6 @@ ${contextText}`;
3225
2959
  const body = this.block();
3226
2960
  return new WhileNode(condition, body.statements, whileToken);
3227
2961
  }
3228
- forStatement() {
3229
- const forToken = this.eat("RESERVED_KEYWORD" /* RESERVED_KEYWORD */);
3230
- if (!this.isIdentifierToken()) {
3231
- throw new ParserError("PARSER_EXPECTED_TOKEN_TYPE" /* EXPECTED_TOKEN_TYPE */, {
3232
- token: this.currentToken,
3233
- data: { expectedType: "identifier", actualType: this.currentToken.type }
3234
- });
3235
- }
3236
- const firstVar = this.currentToken.value;
3237
- this.eat(this.currentToken.type);
3238
- let indexVar = null;
3239
- if (this.currentToken.type === "COMMA" /* COMMA */) {
3240
- this.eat("COMMA" /* COMMA */);
3241
- if (!this.isIdentifierToken()) {
3242
- throw new ParserError("PARSER_EXPECTED_TOKEN_TYPE" /* EXPECTED_TOKEN_TYPE */, {
3243
- token: this.currentToken,
3244
- data: { expectedType: "identifier", actualType: this.currentToken.type }
3245
- });
3246
- }
3247
- indexVar = this.currentToken.value;
3248
- this.eat(this.currentToken.type);
3249
- }
3250
- if (!this.isIdentifierToken() || this.currentToken.value !== "in") {
3251
- throw new ParserError("PARSER_EXPECTED_TOKEN_TYPE" /* EXPECTED_TOKEN_TYPE */, {
3252
- token: this.currentToken,
3253
- data: { expectedType: "'in'", actualType: this.currentToken.value }
3254
- });
3255
- }
3256
- this.eat(this.currentToken.type);
3257
- const collection = this.expr();
3258
- const body = this.block();
3259
- if (this.currentToken.type === "SEMICOLON" /* SEMICOLON */) {
3260
- this.eat("SEMICOLON" /* SEMICOLON */);
3261
- }
3262
- return new ForEachNode(
3263
- firstVar,
3264
- indexVar,
3265
- collection,
3266
- body.statements,
3267
- forToken
3268
- );
3269
- }
3270
2962
  ifStatement() {
3271
2963
  const ifToken = this.eat("RESERVED_KEYWORD" /* RESERVED_KEYWORD */);
3272
2964
  this.eat("LPAREN" /* LPAREN */);
@@ -3295,21 +2987,6 @@ ${contextText}`;
3295
2987
  this.eat("RBLOCK" /* RBLOCK */);
3296
2988
  return new BlockNode(statements);
3297
2989
  }
3298
- // Explicit list literal: [expr, expr, ...]
3299
- explicitList() {
3300
- const token = this.currentToken;
3301
- this.eat("LBLOCK" /* LBLOCK */);
3302
- const elements = [];
3303
- if (this.currentToken.type !== "RBLOCK" /* RBLOCK */) {
3304
- elements.push(this.expr());
3305
- while (this.currentToken.type === "COMMA" /* COMMA */) {
3306
- this.eat("COMMA" /* COMMA */);
3307
- elements.push(this.expr());
3308
- }
3309
- }
3310
- this.eat("RBLOCK" /* RBLOCK */);
3311
- return new ListNode(elements, token);
3312
- }
3313
2990
  // implicit_list_expr : factor ((COMMA) factor)*
3314
2991
  implicitListExpr() {
3315
2992
  const token = this.currentToken;
@@ -3338,8 +3015,6 @@ ${contextText}`;
3338
3015
  let node = this.comparison();
3339
3016
  while (this.currentToken.type === "OPERATION" /* OPERATION */ && (this.currentToken.value === "+" /* ADD */ || this.currentToken.value === "-" /* SUBTRACT */)) {
3340
3017
  const token = this.eat("OPERATION" /* OPERATION */);
3341
- const partial = this.tryRecoverMissingOperand(node, token);
3342
- if (partial) return partial;
3343
3018
  node = new BinOpNode(node, token, this.comparison());
3344
3019
  }
3345
3020
  return node;
@@ -3349,8 +3024,6 @@ ${contextText}`;
3349
3024
  let node = this.term();
3350
3025
  while (this.currentToken.type === "IS_EQ" /* IS_EQ */ || this.currentToken.type === "IS_NOT_EQ" /* IS_NOT_EQ */ || this.currentToken.type === "GT" /* IS_GT */ || this.currentToken.type === "LT" /* IS_LT */ || this.currentToken.type === "IS_GT_EQ" /* IS_GT_EQ */ || this.currentToken.type === "IS_LT_EQ" /* IS_LT_EQ */) {
3351
3026
  const token = this.eat(this.currentToken.type);
3352
- const partial = this.tryRecoverMissingOperand(node, token);
3353
- if (partial) return partial;
3354
3027
  node = new BinOpNode(node, token, this.term());
3355
3028
  }
3356
3029
  return node;
@@ -3360,8 +3033,6 @@ ${contextText}`;
3360
3033
  let node = this.power();
3361
3034
  while (this.currentToken.type === "OPERATION" /* OPERATION */ && (this.currentToken.value === "*" /* MULTIPLY */ || this.currentToken.value === "/" /* DIVIDE */)) {
3362
3035
  const token = this.eat("OPERATION" /* OPERATION */);
3363
- const partial = this.tryRecoverMissingOperand(node, token);
3364
- if (partial) return partial;
3365
3036
  node = new BinOpNode(node, token, this.power());
3366
3037
  }
3367
3038
  return node;
@@ -3371,8 +3042,6 @@ ${contextText}`;
3371
3042
  let node = this.factor();
3372
3043
  while (this.currentToken.type === "OPERATION" /* OPERATION */ && this.currentToken.value === "^" /* POWER */) {
3373
3044
  const token = this.eat("OPERATION" /* OPERATION */);
3374
- const partial = this.tryRecoverMissingOperand(node, token);
3375
- if (partial) return partial;
3376
3045
  node = new BinOpNode(node, token, this.factor());
3377
3046
  }
3378
3047
  return node;
@@ -3401,19 +3070,8 @@ ${contextText}`;
3401
3070
  // | HEX_COLOR
3402
3071
  factor() {
3403
3072
  const token = this.currentToken;
3404
- if (token.type === "LBLOCK" /* LBLOCK */) {
3405
- return this.explicitList();
3406
- }
3407
3073
  if (token.type === "OPERATION" /* OPERATION */ && (token.value === "+" /* ADD */ || token.value === "-" /* SUBTRACT */ || token.value === "!" /* LOGIC_NOT */)) {
3408
3074
  this.eat("OPERATION" /* OPERATION */);
3409
- if (this.tolerant && this.currentToken.type === "EOF" /* EOF */) {
3410
- this.incompleteInfo.push({
3411
- type: "missing_operand" /* MISSING_OPERAND */,
3412
- startPos: token.pos,
3413
- endPos: token.endPos
3414
- });
3415
- return new PartialUnaryOpNode(token);
3416
- }
3417
3075
  return new UnaryOpNode(token, this.factor());
3418
3076
  }
3419
3077
  if (token.type === "RESERVED_KEYWORD" /* RESERVED_KEYWORD */ && (token.value === "true" /* TRUE */ || token.value === "false" /* FALSE */)) {
@@ -3428,34 +3086,14 @@ ${contextText}`;
3428
3086
  return this.number();
3429
3087
  }
3430
3088
  if (token.type === "LPAREN" /* LPAREN */) {
3431
- const lparenToken = token;
3432
3089
  this.eat("LPAREN" /* LPAREN */);
3433
- if (this.tolerant && this.currentToken.type === "EOF" /* EOF */) {
3434
- this.incompleteInfo.push({
3435
- type: "unclosed_paren" /* UNCLOSED_PAREN */,
3436
- startPos: lparenToken.pos
3437
- });
3438
- return new PartialParenNode(new NullNode(lparenToken), lparenToken);
3439
- }
3440
3090
  const node = this.expr();
3441
- if (this.tolerant && this.currentToken.type === "EOF" /* EOF */) {
3442
- this.incompleteInfo.push({
3443
- type: "unclosed_paren" /* UNCLOSED_PAREN */,
3444
- startPos: lparenToken.pos
3445
- });
3446
- return new PartialParenNode(node, lparenToken);
3447
- }
3448
3091
  this.eat("RPAREN" /* RPAREN */);
3449
3092
  if (this.currentToken.type === "FORMAT" /* FORMAT */) {
3450
3093
  return this.format(node);
3451
3094
  }
3452
3095
  return node;
3453
3096
  }
3454
- if (token.type === "PARTIAL_REFERENCE" /* PARTIAL_REFERENCE */) {
3455
- let node = this.reference();
3456
- node = this.attributeAccess(node);
3457
- return node;
3458
- }
3459
3097
  if (token.type === "REFERENCE" /* REFERENCE */) {
3460
3098
  let node = this.reference();
3461
3099
  node = this.attributeAccess(node);
@@ -3465,18 +3103,6 @@ ${contextText}`;
3465
3103
  this.eat("HEX_COLOR" /* HEX_COLOR */);
3466
3104
  return new HexColorNode(token);
3467
3105
  }
3468
- if (token.type === "PARTIAL_STRING" /* PARTIAL_STRING */) {
3469
- this.eat("PARTIAL_STRING" /* PARTIAL_STRING */);
3470
- const sourceText = this.lexer.getSourceInfo().text;
3471
- const quoteType = sourceText[token.pos] ?? '"';
3472
- this.incompleteInfo.push({
3473
- type: "unclosed_string" /* UNCLOSED_STRING */,
3474
- startPos: token.pos,
3475
- endPos: token.endPos,
3476
- partialValue: token.value
3477
- });
3478
- return new PartialStringNode(token.value, quoteType, token);
3479
- }
3480
3106
  if (this.isIdentifierToken(token)) {
3481
3107
  this.eat(token.type);
3482
3108
  let node;
@@ -3488,39 +3114,27 @@ ${contextText}`;
3488
3114
  node = this.attributeAccess(node);
3489
3115
  return node;
3490
3116
  }
3491
- if (token.type === "TEMPLATE_STRING" /* TEMPLATE_STRING */) {
3492
- return this.templateString();
3493
- }
3494
3117
  if (token.type === "EXPLICIT_STRING" /* EXPLICIT_STRING */) {
3495
3118
  this.eat("EXPLICIT_STRING" /* EXPLICIT_STRING */);
3496
3119
  let node = new StringNode(token);
3497
3120
  node = this.attributeAccess(node);
3498
3121
  return node;
3499
3122
  }
3500
- if (this.tolerant && token.type === "EOF" /* EOF */) {
3501
- return new NullNode(token);
3502
- }
3503
3123
  this.error("PARSER_UNEXPECTED_TOKEN" /* UNEXPECTED_TOKEN */, { token: String(token.value) });
3504
3124
  }
3505
3125
  attributeAccess(leftNode) {
3506
3126
  let node = leftNode;
3507
3127
  while (this.currentToken.type === "DOT" /* DOT */) {
3508
- const dotToken = this.eat("DOT" /* DOT */);
3509
- if (this.tolerant && this.currentToken.type === "EOF" /* EOF */) {
3510
- this.incompleteInfo.push({
3511
- type: "trailing_dot" /* TRAILING_DOT */,
3512
- startPos: dotToken.pos,
3513
- endPos: dotToken.endPos
3514
- });
3515
- break;
3516
- }
3128
+ this.eat("DOT" /* DOT */);
3517
3129
  if (this.isIdentifierToken()) {
3518
3130
  const nextToken = this.lexer.peekToken();
3519
3131
  if (nextToken && nextToken.type === "LPAREN" /* LPAREN */) {
3520
3132
  const methodName = this.currentToken.value;
3521
3133
  this.eat(this.currentToken.type);
3522
- const funcCall = this.functionCall({ ...this.currentToken, value: methodName });
3523
- node = new AttributeAccessNode(node, funcCall);
3134
+ node = new AttributeAccessNode(
3135
+ node,
3136
+ this.functionCall({ ...this.currentToken, value: methodName })
3137
+ );
3524
3138
  } else {
3525
3139
  const attrToken = this.currentToken;
3526
3140
  this.eat(this.currentToken.type);
@@ -3534,14 +3148,6 @@ ${contextText}`;
3534
3148
  this.eat("LPAREN" /* LPAREN */);
3535
3149
  const args = [];
3536
3150
  while (this.currentToken.type !== "RPAREN" /* RPAREN */) {
3537
- if (this.tolerant && this.currentToken.type === "EOF" /* EOF */) {
3538
- this.incompleteInfo.push({
3539
- type: "unclosed_function" /* UNCLOSED_FUNCTION */,
3540
- startPos: functionName.pos,
3541
- partialValue: functionName.value
3542
- });
3543
- return new PartialFunctionCallNode(functionName.value, args, functionName);
3544
- }
3545
3151
  if (this.currentToken.type === "COMMA" /* COMMA */) {
3546
3152
  this.eat("COMMA" /* COMMA */);
3547
3153
  }
@@ -3550,126 +3156,7 @@ ${contextText}`;
3550
3156
  this.eat("RPAREN" /* RPAREN */);
3551
3157
  return new FunctionCallNode(functionName.value, args, functionName);
3552
3158
  }
3553
- /**
3554
- * Parse a TEMPLATE_STRING token into a TemplateStringNode.
3555
- * Scans the raw content for:
3556
- * - {ref.path} → ReferenceNode
3557
- * - ${expression} → parsed sub-expression
3558
- * - \{ \${ \` \\ → escaped literals (backslash removed)
3559
- * - everything else → literal StringNode segments
3560
- */
3561
- templateString() {
3562
- const token = this.currentToken;
3563
- const raw = token.value;
3564
- this.eat("TEMPLATE_STRING" /* TEMPLATE_STRING */);
3565
- const parts = [];
3566
- let literal = "";
3567
- let i = 0;
3568
- const flushLiteral = () => {
3569
- if (literal.length > 0) {
3570
- parts.push(new StringNode({ ...token, value: literal }));
3571
- literal = "";
3572
- }
3573
- };
3574
- while (i < raw.length) {
3575
- const ch = raw[i];
3576
- if (ch === "\\" && i + 1 < raw.length) {
3577
- const next = raw[i + 1];
3578
- if (next === "{" || next === "`" || next === "\\") {
3579
- literal += next;
3580
- i += 2;
3581
- continue;
3582
- }
3583
- if (next === "$") {
3584
- if (i + 2 < raw.length && raw[i + 2] === "{") {
3585
- literal += "${";
3586
- i += 3;
3587
- } else {
3588
- literal += "$";
3589
- i += 2;
3590
- }
3591
- continue;
3592
- }
3593
- }
3594
- if (ch === "$" && i + 1 < raw.length && raw[i + 1] === "{") {
3595
- flushLiteral();
3596
- const start = i + 2;
3597
- let depth = 1;
3598
- let j = start;
3599
- while (j < raw.length && depth > 0) {
3600
- if (raw[j] === "`") {
3601
- this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3602
- message: "Nested template strings are not allowed inside ${...}"
3603
- });
3604
- }
3605
- if (raw[j] === "{") depth++;
3606
- else if (raw[j] === "}") depth--;
3607
- if (depth > 0) j++;
3608
- }
3609
- if (depth !== 0) {
3610
- this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3611
- message: "Unterminated ${...} in template string"
3612
- });
3613
- }
3614
- const exprStr = raw.slice(start, j);
3615
- const subLexer = new Lexer(exprStr);
3616
- const subParser = new _Parser(subLexer);
3617
- const exprNode = subParser.expr();
3618
- for (const ref of subParser.requiredReferences) {
3619
- this.requiredReferences.add(ref);
3620
- }
3621
- parts.push(exprNode);
3622
- i = j + 1;
3623
- continue;
3624
- }
3625
- if (ch === "{") {
3626
- flushLiteral();
3627
- const start = i + 1;
3628
- let j = start;
3629
- while (j < raw.length && raw[j] !== "}") {
3630
- if (raw[j] === "{") {
3631
- this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3632
- message: "Nested braces in template reference"
3633
- });
3634
- }
3635
- j++;
3636
- }
3637
- if (j >= raw.length) {
3638
- this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3639
- message: "Unterminated {ref} in template string"
3640
- });
3641
- }
3642
- let refPath = raw.slice(start, j);
3643
- refPath = refPath.replace(/[ \t]/g, "");
3644
- if (refPath.length === 0) {
3645
- this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3646
- message: "Empty reference in template string"
3647
- });
3648
- }
3649
- this.requiredReferences.add(refPath);
3650
- parts.push(
3651
- new ReferenceNode({
3652
- ...token,
3653
- type: "REFERENCE" /* REFERENCE */,
3654
- value: refPath
3655
- })
3656
- );
3657
- i = j + 1;
3658
- continue;
3659
- }
3660
- literal += ch;
3661
- i++;
3662
- }
3663
- flushLiteral();
3664
- if (parts.length === 1 && parts[0] instanceof StringNode) {
3665
- return parts[0];
3666
- }
3667
- return new TemplateStringNode(parts, token);
3668
- }
3669
3159
  parse(inlineMode = false) {
3670
- if (this.tolerant && !inlineMode) {
3671
- this.error("PARSER_TOLERANT_REQUIRES_INLINE" /* TOLERANT_REQUIRES_INLINE */);
3672
- }
3673
3160
  if (this.currentToken.type === "EOF" /* EOF */) return null;
3674
3161
  if (inlineMode) return this.listExpr();
3675
3162
  const node = this.statementsList();
@@ -3715,11 +3202,49 @@ function renameReferences(originalValue, ast, renameMap) {
3715
3202
  }
3716
3203
  return result;
3717
3204
  }
3718
- var parseColorSpec = Color.parseColorSpec;
3719
- Color.safeParseColorSpec;
3720
- Color.parseColorSpec;
3205
+ var ScriptBlockSchema = type({
3206
+ type: "string",
3207
+ script: "string"
3208
+ });
3209
+ var InitializerSchema = type({
3210
+ "title?": "string",
3211
+ keyword: "string",
3212
+ "description?": "string",
3213
+ // schema: type({ "...": "unknown" }),
3214
+ script: ScriptBlockSchema
3215
+ });
3216
+ var ConversionSchema = type({
3217
+ source: "string",
3218
+ target: "string",
3219
+ "description?": "string",
3220
+ lossless: "boolean",
3221
+ script: ScriptBlockSchema
3222
+ });
3721
3223
  var validSchemaTypes = ["number", "string", "color"];
3722
- var specName = Color.specName;
3224
+ type({
3225
+ type: "'number' | 'string' | 'color'"
3226
+ });
3227
+ var SpecSchemaSchema = type({
3228
+ type: "'object'",
3229
+ properties: type("Record<string, unknown>").narrow((v) => {
3230
+ if (!isObject(v)) return false;
3231
+ return Object.values(v).every(
3232
+ (prop) => ["number", "string", "color"].includes(prop?.type)
3233
+ );
3234
+ }),
3235
+ "required?": "string[]",
3236
+ "order?": "string[]",
3237
+ "additionalProperties?": "boolean"
3238
+ });
3239
+ var ColorSpecificationSchema = type({
3240
+ name: "string",
3241
+ type: "'color'",
3242
+ "description?": "string",
3243
+ "schema?": SpecSchemaSchema,
3244
+ initializers: InitializerSchema.array(),
3245
+ conversions: ConversionSchema.array()
3246
+ });
3247
+ var specName = (spec) => spec.name.toLowerCase();
3723
3248
 
3724
3249
  // src/utils/schema-uri.ts
3725
3250
  var DEFAULT_REGISTRY_URL = "https://schema.tokenscript.dev.gcp.tokens.studio";
@@ -4139,11 +3664,6 @@ var BaseManager = class {
4139
3664
 
4140
3665
  // src/interpreter/config/managers/functions/builtin/math.ts
4141
3666
  function extractNumber(arg, functionName) {
4142
- if (arg === void 0 || arg === null) {
4143
- throw new InterpreterError("FN_EXPECTS_NUMBER_ARGUMENTS" /* EXPECTS_NUMBER_ARGUMENTS */, {
4144
- data: { functionName }
4145
- });
4146
- }
4147
3667
  if (arg instanceof NumberSymbol) return arg.value;
4148
3668
  if (arg instanceof NumberWithUnitSymbol) return arg.value;
4149
3669
  if (typeof arg.value === "number") return arg.value;
@@ -4398,10 +3918,21 @@ var mathFunctions = {
4398
3918
  // Constants
4399
3919
  pi: () => new NumberSymbol(Math.PI)
4400
3920
  };
4401
- var parseFunctionSpec = Fn.parseFunctionSpec;
4402
- Fn.safeParseFunctionSpec;
4403
- Fn.parseFunctionSpec;
4404
- Fn.specName;
3921
+ var FunctionSpecificationSchema = type({
3922
+ name: "string",
3923
+ type: "'function'",
3924
+ "input?": {
3925
+ type: "'object'",
3926
+ "properties?": "Record<string, unknown>"
3927
+ },
3928
+ script: {
3929
+ type: "string",
3930
+ script: "string"
3931
+ },
3932
+ keyword: "string",
3933
+ "description?": "string",
3934
+ "requirements?": "string[]"
3935
+ });
4405
3936
 
4406
3937
  // src/interpreter/config/managers/functions/manager.ts
4407
3938
  var FunctionsManager = class _FunctionsManager extends BaseManager {
@@ -4423,12 +3954,18 @@ var FunctionsManager = class _FunctionsManager extends BaseManager {
4423
3954
  }
4424
3955
  register(name, spec) {
4425
3956
  let parsedSpec;
4426
- try {
4427
- const input = typeof spec === "string" ? JSON.parse(spec) : spec;
4428
- parsedSpec = parseFunctionSpec(input);
4429
- } catch (err) {
4430
- const summary = err instanceof ZodError ? err.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
4431
- throw new Error(`Invalid function specification for ${name}: ${summary}`);
3957
+ if (typeof spec === "string") {
3958
+ const parseResult = FunctionSpecificationSchema(JSON.parse(spec));
3959
+ if (parseResult instanceof type.errors) {
3960
+ throw new Error(`Invalid function specification for ${name}: ${parseResult.summary}`);
3961
+ }
3962
+ parsedSpec = parseResult;
3963
+ } else {
3964
+ const parseResult = FunctionSpecificationSchema(spec);
3965
+ if (parseResult instanceof type.errors) {
3966
+ throw new Error(`Invalid function specification for ${name}: ${parseResult.summary}`);
3967
+ }
3968
+ parsedSpec = parseResult;
4432
3969
  }
4433
3970
  const functionName = parsedSpec.keyword.toLowerCase();
4434
3971
  this.specs.set(functionName, parsedSpec);
@@ -4499,72 +4036,6 @@ var FunctionsManager = class _FunctionsManager extends BaseManager {
4499
4036
  this.registerFunction("is_color", (arg) => {
4500
4037
  return new BooleanSymbol(arg.type === "Color");
4501
4038
  });
4502
- this.registerFunction("range", (...args) => {
4503
- if (args.length < 1 || args.length > 2) {
4504
- throw new InterpreterError("FN_REQUIRES_MIN_ARGUMENTS" /* REQUIRES_MIN_ARGUMENTS */, {
4505
- data: { functionName: "range", minArgs: 1 }
4506
- });
4507
- }
4508
- let start;
4509
- let end;
4510
- if (args.length === 1) {
4511
- if (!(args[0] instanceof NumberSymbol)) {
4512
- throw new InterpreterError("FN_EXPECTS_TYPE_ARGUMENT" /* EXPECTS_TYPE_ARGUMENT */, {
4513
- data: { functionName: "range", expectedType: "Number", argumentPosition: "first" }
4514
- });
4515
- }
4516
- const v = args[0].value;
4517
- if (v !== Math.trunc(v) || Number.isNaN(v) || !Number.isFinite(v) || v < 0 || v > 1e6) {
4518
- throw new InterpreterError("FN_ARGUMENT_OUT_OF_RANGE" /* ARGUMENT_OUT_OF_RANGE */, {
4519
- data: {
4520
- functionName: "range",
4521
- constraint: `count must be a non-negative integer <= 1000000, got ${v}`
4522
- }
4523
- });
4524
- }
4525
- start = 0;
4526
- end = v;
4527
- } else {
4528
- if (!(args[0] instanceof NumberSymbol)) {
4529
- throw new InterpreterError("FN_EXPECTS_TYPE_ARGUMENT" /* EXPECTS_TYPE_ARGUMENT */, {
4530
- data: { functionName: "range", expectedType: "Number", argumentPosition: "first" }
4531
- });
4532
- }
4533
- if (!(args[1] instanceof NumberSymbol)) {
4534
- throw new InterpreterError("FN_EXPECTS_TYPE_ARGUMENT" /* EXPECTS_TYPE_ARGUMENT */, {
4535
- data: { functionName: "range", expectedType: "Number", argumentPosition: "second" }
4536
- });
4537
- }
4538
- const sv = args[0].value;
4539
- const ev = args[1].value;
4540
- if (sv !== Math.trunc(sv) || ev !== Math.trunc(ev) || Number.isNaN(sv) || Number.isNaN(ev) || !Number.isFinite(sv) || !Number.isFinite(ev)) {
4541
- throw new InterpreterError("FN_ARGUMENT_OUT_OF_RANGE" /* ARGUMENT_OUT_OF_RANGE */, {
4542
- data: {
4543
- functionName: "range",
4544
- constraint: `arguments must be integers, got ${sv} and ${ev}`
4545
- }
4546
- });
4547
- }
4548
- if (ev - sv > 1e6) {
4549
- throw new InterpreterError("FN_ARGUMENT_OUT_OF_RANGE" /* ARGUMENT_OUT_OF_RANGE */, {
4550
- data: {
4551
- functionName: "range",
4552
- constraint: `size exceeds limit (1000000), got ${ev - sv}`
4553
- }
4554
- });
4555
- }
4556
- start = sv;
4557
- end = ev;
4558
- }
4559
- if (end < start) {
4560
- return new ListSymbol([], false);
4561
- }
4562
- const elements = [];
4563
- for (let i = start; i < end; i++) {
4564
- elements.push(new NumberSymbol(i));
4565
- }
4566
- return new ListSymbol(elements, false);
4567
- });
4568
4039
  }
4569
4040
  registerFunction(name, impl) {
4570
4041
  this.functionMap.set(name.toLowerCase(), impl);
@@ -4616,33 +4087,26 @@ var FunctionsManager = class _FunctionsManager extends BaseManager {
4616
4087
  getFunctionNames() {
4617
4088
  return Array.from(this.functionMap.keys());
4618
4089
  }
4619
- getFunctionSchemas() {
4620
- return this.specs;
4621
- }
4622
- /**
4623
- * Validate that a function call has the correct number of arguments
4624
- * based on its schema spec. Only validates schema-registered functions
4625
- * (not builtins which handle their own argument validation).
4626
- */
4627
- validateFunctionArgs(name, args, token) {
4628
- const fnName = name.toLowerCase();
4629
- const spec = this.specs.get(fnName);
4630
- if (!spec?.input?.properties) return;
4631
- const requiredCount = Object.values(spec.input.properties).filter(
4632
- (prop) => !prop?.optional
4633
- ).length;
4634
- if (args.length < requiredCount) {
4635
- throw new InterpreterError("FN_REQUIRES_MIN_ARGUMENTS" /* REQUIRES_MIN_ARGUMENTS */, {
4636
- token,
4637
- data: { functionName: name, minArgs: requiredCount }
4638
- });
4639
- }
4640
- }
4641
4090
  };
4642
- var parseUnitSpec = Unit.parseUnitSpec;
4643
- Unit.safeParseUnitSpec;
4644
- Unit.parseUnitSpec;
4645
- var specName3 = Unit.specName;
4091
+ var ScriptBlockSchema2 = type({
4092
+ "type?": "string",
4093
+ script: "string"
4094
+ });
4095
+ var ConversionSchema2 = type({
4096
+ source: "string",
4097
+ target: "string",
4098
+ script: ScriptBlockSchema2,
4099
+ "description?": "string"
4100
+ });
4101
+ var UnitSpecificationSchema = type({
4102
+ name: "string",
4103
+ type: "'absolute' | 'relative'",
4104
+ keyword: "string",
4105
+ "description?": "string",
4106
+ "conversions?": ConversionSchema2.array(),
4107
+ "to_absolute?": ScriptBlockSchema2
4108
+ });
4109
+ var specName2 = (spec) => spec.name.toLowerCase();
4646
4110
 
4647
4111
  // src/interpreter/config/managers/unit/manager.ts
4648
4112
  var PIXEL_UNIT = buildSchemaUri({
@@ -4721,7 +4185,7 @@ var UnitManager = class _UnitManager extends BaseManager {
4721
4185
  }
4722
4186
  }
4723
4187
  getSpecName(spec) {
4724
- return specName3(spec);
4188
+ return specName2(spec);
4725
4189
  }
4726
4190
  /**
4727
4191
  * Creates a clone of this class to be passed down to initializers and conversion functions
@@ -4755,19 +4219,26 @@ var UnitManager = class _UnitManager extends BaseManager {
4755
4219
  }
4756
4220
  register(uri, spec) {
4757
4221
  let parsedSpec;
4758
- try {
4759
- const input = typeof spec === "string" ? JSON.parse(spec) : spec;
4760
- parsedSpec = parseUnitSpec(input);
4761
- } catch (err) {
4762
- const summary = err instanceof ZodError ? err.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
4763
- const jsonSuffix = typeof spec === "string" ? `
4222
+ if (typeof spec === "string") {
4223
+ const parseResult = UnitSpecificationSchema(JSON.parse(spec));
4224
+ if (parseResult instanceof type.errors) {
4225
+ throw new Error(
4226
+ `Invalid unit specification for URI ${uri}: ${parseResult.summary}
4764
4227
 
4765
4228
  Json:
4766
- ${spec}` : "";
4767
- throw new Error(`Invalid unit specification for URI ${uri}: ${summary}${jsonSuffix}`);
4229
+ ${spec}`
4230
+ );
4231
+ }
4232
+ parsedSpec = parseResult;
4233
+ } else {
4234
+ const parseResult = UnitSpecificationSchema(spec);
4235
+ if (parseResult instanceof type.errors) {
4236
+ throw new Error(`Invalid unit specification for URI ${uri}: ${parseResult.summary}`);
4237
+ }
4238
+ parsedSpec = parseResult;
4768
4239
  }
4769
4240
  this.specs.set(uri, parsedSpec);
4770
- this.specTypes.set(specName3(parsedSpec), uri);
4241
+ this.specTypes.set(specName2(parsedSpec), uri);
4771
4242
  this.unitKeywords.set(parsedSpec.keyword.toUpperCase(), uri);
4772
4243
  this.registerConversions(uri, parsedSpec);
4773
4244
  return parsedSpec;
@@ -5038,16 +4509,23 @@ var ColorManager = class _ColorManager extends BaseManager {
5038
4509
  }
5039
4510
  register(uri, spec) {
5040
4511
  let parsedSpec;
5041
- try {
5042
- const input = typeof spec === "string" ? JSON.parse(spec) : spec;
5043
- parsedSpec = parseColorSpec(input);
5044
- } catch (err) {
5045
- const summary = err instanceof ZodError ? err.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
5046
- const jsonSuffix = typeof spec === "string" ? `
4512
+ if (typeof spec === "string") {
4513
+ const parseResult = ColorSpecificationSchema(JSON.parse(spec));
4514
+ if (parseResult instanceof type.errors) {
4515
+ throw new Error(
4516
+ `Invalid color specification for URI ${uri}: ${parseResult.summary}
5047
4517
 
5048
4518
  Json:
5049
- ${spec}` : "";
5050
- throw new Error(`Invalid color specification for URI ${uri}: ${summary}${jsonSuffix}`);
4519
+ ${spec}`
4520
+ );
4521
+ }
4522
+ parsedSpec = parseResult;
4523
+ } else {
4524
+ const parseResult = ColorSpecificationSchema(spec);
4525
+ if (parseResult instanceof type.errors) {
4526
+ throw new Error(`Invalid color specification for URI ${uri}: ${parseResult.summary}`);
4527
+ }
4528
+ parsedSpec = parseResult;
5051
4529
  }
5052
4530
  this.specs.set(uri, parsedSpec);
5053
4531
  this.specTypes.set(specName(parsedSpec), uri);
@@ -5055,8 +4533,8 @@ ${spec}` : "";
5055
4533
  this.registerConversions(uri, parsedSpec);
5056
4534
  return parsedSpec;
5057
4535
  }
5058
- getSpecByType(type) {
5059
- const uri = this.specTypes.get(type.toLowerCase());
4536
+ getSpecByType(type9) {
4537
+ const uri = this.specTypes.get(type9.toLowerCase());
5060
4538
  if (!uri) return;
5061
4539
  return this.getSpec(uri);
5062
4540
  }
@@ -5269,14 +4747,28 @@ ${spec}` : "";
5269
4747
  }
5270
4748
  return "";
5271
4749
  }
5272
- getColorSchemas() {
5273
- return this.specs;
5274
- }
5275
4750
  };
5276
- var parseTokenSpec = Token.parseTokenSpec;
5277
- Token.safeParseTokenSpec;
5278
- Token.parseTokenSpec;
5279
- var specName4 = Token.specName;
4751
+ var SpecSchemaSchema2 = type({
4752
+ type: "'object' | 'number' | 'string' | 'list'",
4753
+ "properties?": "Record<string, unknown>",
4754
+ // Simplified validation
4755
+ "validations?": "Record<string, string>",
4756
+ "required?": "string[]",
4757
+ "order?": "string[]",
4758
+ "additionalProperties?": "boolean",
4759
+ "items?": "unknown"
4760
+ // For list types - validated at runtime
4761
+ });
4762
+ var TokenSpecificationSchema = type({
4763
+ name: "string",
4764
+ type: "'token'",
4765
+ "description?": "string",
4766
+ "url?": "string",
4767
+ "schema?": SpecSchemaSchema2,
4768
+ "validation?": "string | unknown"
4769
+ // Allow string or object, validated at runtime in manager
4770
+ });
4771
+ var specName3 = (spec) => spec.name.toLowerCase();
5280
4772
 
5281
4773
  // src/interpreter/config/managers/token/manager.ts
5282
4774
  var MAX_VALIDATION_DEPTH = 10;
@@ -5301,10 +4793,10 @@ var TokenManager = class _TokenManager extends BaseManager {
5301
4793
  this.validationInterpreterCache = /* @__PURE__ */ new Map();
5302
4794
  }
5303
4795
  getSpecName(spec) {
5304
- return specName4(spec);
4796
+ return specName3(spec);
5305
4797
  }
5306
- getSpecByType(type) {
5307
- const uri = this.specTypes.get(type.toLowerCase());
4798
+ getSpecByType(type9) {
4799
+ const uri = this.specTypes.get(type9.toLowerCase());
5308
4800
  if (!uri) return;
5309
4801
  return this.getSpec(uri);
5310
4802
  }
@@ -5320,18 +4812,25 @@ var TokenManager = class _TokenManager extends BaseManager {
5320
4812
  }
5321
4813
  register(uri, spec) {
5322
4814
  let parsedSpec;
5323
- try {
5324
- const input = typeof spec === "string" ? JSON.parse(spec) : spec;
5325
- parsedSpec = parseTokenSpec(input);
5326
- } catch (err) {
5327
- const summary = err instanceof ZodError ? err.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ") : err instanceof Error ? err.message : String(err);
5328
- const jsonSuffix = typeof spec === "string" ? `
4815
+ if (typeof spec === "string") {
4816
+ const parseResult = TokenSpecificationSchema(JSON.parse(spec));
4817
+ if (parseResult instanceof type.errors) {
4818
+ throw new Error(
4819
+ `Invalid token specification for URI ${uri}: ${parseResult.summary}
5329
4820
  Json:
5330
- ${spec}` : "";
5331
- throw new Error(`Invalid token specification for URI ${uri}: ${summary}${jsonSuffix}`);
4821
+ ${spec}`
4822
+ );
4823
+ }
4824
+ parsedSpec = parseResult;
4825
+ } else {
4826
+ const parseResult = TokenSpecificationSchema(spec);
4827
+ if (parseResult instanceof type.errors) {
4828
+ throw new Error(`Invalid token specification for URI ${uri}: ${parseResult.summary}`);
4829
+ }
4830
+ parsedSpec = parseResult;
5332
4831
  }
5333
4832
  this.specs.set(uri, parsedSpec);
5334
- this.specTypes.set(specName4(parsedSpec), uri);
4833
+ this.specTypes.set(specName3(parsedSpec), uri);
5335
4834
  if (parsedSpec.validation) {
5336
4835
  this.registerValidation(parsedSpec.name, parsedSpec.validation);
5337
4836
  }
@@ -5367,8 +4866,8 @@ ${spec}` : "";
5367
4866
  return this.extractErrorTypesFromAST(tokenType);
5368
4867
  }
5369
4868
  const allErrors = /* @__PURE__ */ new Set();
5370
- for (const type of this.validationScripts.keys()) {
5371
- for (const error of this.extractErrorTypesFromAST(type)) {
4869
+ for (const type9 of this.validationScripts.keys()) {
4870
+ for (const error of this.extractErrorTypesFromAST(type9)) {
5372
4871
  allErrors.add(error);
5373
4872
  }
5374
4873
  }
@@ -5921,9 +5420,6 @@ var SymbolTable = class {
5921
5420
  isDefined(name) {
5922
5421
  return !!this.symbols[name.toLowerCase()];
5923
5422
  }
5924
- delete(name) {
5925
- delete this.symbols[name.toLowerCase()];
5926
- }
5927
5423
  reset() {
5928
5424
  this.symbols = {};
5929
5425
  }
@@ -6033,47 +5529,6 @@ var Interpreter = class {
6033
5529
  visitStringNode(node) {
6034
5530
  return new StringSymbol(node.value, this.config);
6035
5531
  }
6036
- visitTemplateStringNode(node) {
6037
- if (node.parts.length === 0) {
6038
- return new StringSymbol("", this.config);
6039
- }
6040
- if (node.parts.length === 1) {
6041
- const val = this.visit(node.parts[0]);
6042
- this.validateTemplateValue(val, node);
6043
- return val;
6044
- }
6045
- let result = "";
6046
- for (const part of node.parts) {
6047
- const val = this.visit(part);
6048
- this.validateTemplateValue(val, node);
6049
- result += val.toString();
6050
- }
6051
- return new StringSymbol(result, this.config);
6052
- }
6053
- /**
6054
- * Validate that a value is a primitive type allowed in template string interpolation.
6055
- * Lists, Dictionaries, and non-hex Colors are rejected.
6056
- */
6057
- validateTemplateValue(val, node) {
6058
- if (val instanceof ListSymbol) {
6059
- throw new InterpreterError("INT_TEMPLATE_INVALID_TYPE" /* TEMPLATE_INVALID_TYPE */, {
6060
- token: node.token,
6061
- data: { valueType: "List" }
6062
- });
6063
- }
6064
- if (val instanceof DictionarySymbol) {
6065
- throw new InterpreterError("INT_TEMPLATE_INVALID_TYPE" /* TEMPLATE_INVALID_TYPE */, {
6066
- token: node.token,
6067
- data: { valueType: "Dictionary" }
6068
- });
6069
- }
6070
- if (val instanceof ColorSymbol && !val.isHex()) {
6071
- throw new InterpreterError("INT_TEMPLATE_INVALID_TYPE" /* TEMPLATE_INVALID_TYPE */, {
6072
- token: node.token,
6073
- data: { valueType: `Color.${val.subType}` }
6074
- });
6075
- }
6076
- }
6077
5532
  /**
6078
5533
  * Bare identifiers are treated as string literals if not found as variables
6079
5534
  * Check symbol table first (variables override references), then references
@@ -6168,7 +5623,6 @@ var Interpreter = class {
6168
5623
  const fnName = node.name.toLowerCase();
6169
5624
  const args = node.args.map((arg) => this.visit(arg));
6170
5625
  if (this.config.functionsManager.hasFunction(fnName)) {
6171
- this.config.functionsManager.validateFunctionArgs(fnName, args, node.token);
6172
5626
  const fn = this.config.functionsManager.getFunction(fnName);
6173
5627
  if (fn) {
6174
5628
  return fn(...args);
@@ -6346,63 +5800,6 @@ var Interpreter = class {
6346
5800
  this.visit(node.body);
6347
5801
  }
6348
5802
  }
6349
- visitForEachNode(node) {
6350
- if (this.symbolTable.isDefined(node.itemVar)) {
6351
- throw new InterpreterError("INT_FOR_EACH_VARIABLE_SHADOW" /* FOR_EACH_VARIABLE_SHADOW */, {
6352
- token: node.token,
6353
- data: { name: node.itemVar }
6354
- });
6355
- }
6356
- if (node.indexVar !== null) {
6357
- if (node.indexVar === node.itemVar) {
6358
- throw new InterpreterError("INT_FOR_EACH_DUPLICATE_VARS" /* FOR_EACH_DUPLICATE_VARS */, {
6359
- token: node.token,
6360
- data: { name: node.itemVar }
6361
- });
6362
- }
6363
- if (this.symbolTable.isDefined(node.indexVar)) {
6364
- throw new InterpreterError("INT_FOR_EACH_VARIABLE_SHADOW" /* FOR_EACH_VARIABLE_SHADOW */, {
6365
- token: node.token,
6366
- data: { name: node.indexVar }
6367
- });
6368
- }
6369
- }
6370
- const collectionVal = this.visit(node.collection);
6371
- if (!(collectionVal instanceof ListSymbol)) {
6372
- throw new InterpreterError("INT_FOR_EACH_NOT_LIST" /* FOR_EACH_NOT_LIST */, {
6373
- token: node.token,
6374
- data: { actualType: collectionVal?.type ?? "null" }
6375
- });
6376
- }
6377
- const elements = collectionVal.value;
6378
- const results = [];
6379
- for (let idx = 0; idx < elements.length; idx++) {
6380
- const item = elements[idx];
6381
- this.symbolTable.set(node.itemVar, item);
6382
- if (node.indexVar !== null) {
6383
- this.symbolTable.set(node.indexVar, new NumberSymbol(idx, this.config));
6384
- }
6385
- let bodyResult = null;
6386
- try {
6387
- bodyResult = this.visit(node.body);
6388
- } catch (e) {
6389
- if (e instanceof ReturnSignal) {
6390
- this.symbolTable.delete(node.itemVar);
6391
- if (node.indexVar !== null) {
6392
- this.symbolTable.delete(node.indexVar);
6393
- }
6394
- throw e;
6395
- }
6396
- throw e;
6397
- }
6398
- results.push(bodyResult ?? new NullSymbol(this.config));
6399
- }
6400
- this.symbolTable.delete(node.itemVar);
6401
- if (node.indexVar !== null) {
6402
- this.symbolTable.delete(node.indexVar);
6403
- }
6404
- return new ListSymbol(results, false, this.config);
6405
- }
6406
5803
  visitIfNode(node) {
6407
5804
  for (const conditionNode of node.conditions) {
6408
5805
  const condition = this.visit(conditionNode.condition);
@@ -6439,6 +5836,6 @@ var Interpreter = class {
6439
5836
  }
6440
5837
  };
6441
5838
 
6442
- export { BaseSymbolType, BooleanSymbol, ColorManager, ColorSymbol, Config, DictionarySymbol, Interpreter, InterpreterError, Lexer, LexerError, ListSymbol, NullSymbol, NumberSymbol, NumberWithUnitSymbol, Parser, ParserError, ProcessorError, StringSymbol, TokenSymbol, getAssignmentInfo, getKeyAlt, getReassignmentInfo, isArray, isBoolean, isLanguageError, isNone, isNull, isNumber, isObject, isString, isTokenscriptSymbol, jsValueToSymbolType, parseColorSpec, parseExpression, parseFunctionSpec, renameReferences, serializeInterpreterResult, stringifyInterpreterResult };
6443
- //# sourceMappingURL=chunk-33CDF4L4.js.map
6444
- //# sourceMappingURL=chunk-33CDF4L4.js.map
5839
+ export { BaseSymbolType, BooleanSymbol, ColorManager, ColorSpecificationSchema, ColorSymbol, Config, DictionarySymbol, FunctionSpecificationSchema, Interpreter, InterpreterError, Lexer, LexerError, ListSymbol, NullSymbol, NumberSymbol, NumberWithUnitSymbol, Parser, ParserError, ProcessorError, StringSymbol, TokenSymbol, getAssignmentInfo, getKeyAlt, getReassignmentInfo, isArray, isBoolean, isLanguageError, isNone, isNull, isNumber, isObject, isString, isTokenscriptSymbol, jsValueToSymbolType, parseExpression, renameReferences, serializeInterpreterResult, stringifyInterpreterResult };
5840
+ //# sourceMappingURL=chunk-P4VLJQEI.js.map
5841
+ //# sourceMappingURL=chunk-P4VLJQEI.js.map