@tokens-studio/tokenscript-interpreter 0.33.0 → 0.34.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 (67) hide show
  1. package/dist/chunk-33CDF4L4.js +6444 -0
  2. package/dist/chunk-33CDF4L4.js.map +1 -0
  3. package/dist/chunk-AXH5N7KV.js +99 -0
  4. package/dist/chunk-AXH5N7KV.js.map +1 -0
  5. package/dist/cli.js +221 -2
  6. package/dist/cli.js.map +1 -1
  7. package/dist/compliance-suite.js +2 -2
  8. package/dist/config-DtbN3iyg.d.ts +918 -0
  9. package/dist/lib/{chunk-QYRJ6NSL.cjs → chunk-LEYHQJTL.cjs} +3 -2
  10. package/dist/lib/chunk-LEYHQJTL.cjs.map +1 -0
  11. package/dist/lib/{chunk-GKSWF7FF.cjs → chunk-LMGHS2NP.cjs} +102 -100
  12. package/dist/lib/chunk-LMGHS2NP.cjs.map +1 -0
  13. package/dist/lib/{chunk-LI2D53SH.js → chunk-LSTH2XJ4.js} +5 -3
  14. package/dist/lib/chunk-LSTH2XJ4.js.map +1 -0
  15. package/dist/lib/{chunk-YD3MIYOO.js → chunk-ODVWXGOM.js} +3 -2
  16. package/dist/lib/chunk-ODVWXGOM.js.map +1 -0
  17. package/dist/lib/{chunk-DFN353G4.js → chunk-RWXDOZAS.js} +225 -4
  18. package/dist/lib/chunk-RWXDOZAS.js.map +1 -0
  19. package/dist/lib/{chunk-AQEJB7EO.cjs → chunk-YCIBJDRB.cjs} +767 -546
  20. package/dist/lib/chunk-YCIBJDRB.cjs.map +1 -0
  21. package/dist/lib/index.cjs +91 -91
  22. package/dist/lib/index.d.cts +4 -4
  23. package/dist/lib/index.d.ts +4 -4
  24. package/dist/lib/index.js +3 -3
  25. package/dist/lib/{interpreter-DNmBc--s.d.ts → interpreter-6QwMkUqD.d.cts} +30 -2
  26. package/dist/lib/{interpreter-CP7CNwDa.d.cts → interpreter-v7WiwSP9.d.ts} +30 -2
  27. package/dist/lib/interpreter.cjs +73 -73
  28. package/dist/lib/interpreter.d.cts +4 -4
  29. package/dist/lib/interpreter.d.ts +4 -4
  30. package/dist/lib/interpreter.js +3 -3
  31. package/dist/lib/processor-node.cjs +12 -12
  32. package/dist/lib/processor-node.d.cts +3 -3
  33. package/dist/lib/processor-node.d.ts +3 -3
  34. package/dist/lib/processor-node.js +3 -3
  35. package/dist/lib/processor.cjs +17 -17
  36. package/dist/lib/processor.d.cts +4 -4
  37. package/dist/lib/processor.d.ts +4 -4
  38. package/dist/lib/processor.js +3 -3
  39. package/dist/lib/schema.cjs +5 -5
  40. package/dist/lib/schema.d.cts +1 -1
  41. package/dist/lib/schema.d.ts +1 -1
  42. package/dist/lib/schema.js +3 -3
  43. package/dist/lib/syntax-highlighting.cjs +15 -15
  44. package/dist/lib/syntax-highlighting.d.cts +1 -1
  45. package/dist/lib/syntax-highlighting.d.ts +1 -1
  46. package/dist/lib/syntax-highlighting.js +2 -2
  47. package/dist/lib/{types-DHgmzR1Z.d.ts → types-BI0AZ4Ej.d.ts} +2 -2
  48. package/dist/lib/{types-BimJex2v.d.cts → types-EB8V9c46.d.cts} +1 -0
  49. package/dist/lib/{types-BimJex2v.d.ts → types-EB8V9c46.d.ts} +1 -0
  50. package/dist/lib/{types-DsJuwrq3.d.cts → types-cFwP43uv.d.cts} +2 -2
  51. package/dist/lib/types.cjs +6 -6
  52. package/dist/lib/types.d.cts +1 -1
  53. package/dist/lib/types.d.ts +1 -1
  54. package/dist/lib/types.js +1 -1
  55. package/dist/processor/index.d.ts +1 -1
  56. package/dist/processor/index.js +2 -2
  57. package/dist/repl.d.ts +1 -1
  58. package/dist/repl.js +2 -2
  59. package/dist/types.d.ts +1 -1
  60. package/dist/types.js +1 -1
  61. package/package.json +1 -1
  62. package/dist/lib/chunk-AQEJB7EO.cjs.map +0 -1
  63. package/dist/lib/chunk-DFN353G4.js.map +0 -1
  64. package/dist/lib/chunk-GKSWF7FF.cjs.map +0 -1
  65. package/dist/lib/chunk-LI2D53SH.js.map +0 -1
  66. package/dist/lib/chunk-QYRJ6NSL.cjs.map +0 -1
  67. package/dist/lib/chunk-YD3MIYOO.js.map +0 -1
@@ -0,0 +1,99 @@
1
+ // src/types.ts
2
+ var Operations = /* @__PURE__ */ ((Operations2) => {
3
+ Operations2["SUBTRACT"] = "-";
4
+ Operations2["ADD"] = "+";
5
+ Operations2["MULTIPLY"] = "*";
6
+ Operations2["DIVIDE"] = "/";
7
+ Operations2["POWER"] = "^";
8
+ Operations2["LOGIC_AND"] = "&&";
9
+ Operations2["LOGIC_OR"] = "||";
10
+ Operations2["LOGIC_NOT"] = "!";
11
+ return Operations2;
12
+ })(Operations || {});
13
+ var SupportedFormats = /* @__PURE__ */ ((SupportedFormats2) => {
14
+ SupportedFormats2["PX"] = "px";
15
+ SupportedFormats2["EM"] = "em";
16
+ SupportedFormats2["REM"] = "rem";
17
+ SupportedFormats2["VW"] = "vw";
18
+ SupportedFormats2["VH"] = "vh";
19
+ SupportedFormats2["PT"] = "pt";
20
+ SupportedFormats2["IN"] = "in";
21
+ SupportedFormats2["CM"] = "cm";
22
+ SupportedFormats2["MM"] = "mm";
23
+ SupportedFormats2["DEG"] = "deg";
24
+ SupportedFormats2["PERCENTAGE"] = "%";
25
+ SupportedFormats2["S"] = "s";
26
+ SupportedFormats2["MS"] = "ms";
27
+ return SupportedFormats2;
28
+ })(SupportedFormats || {});
29
+ var ReservedKeyword = /* @__PURE__ */ ((ReservedKeyword2) => {
30
+ ReservedKeyword2["TRUE"] = "true";
31
+ ReservedKeyword2["FALSE"] = "false";
32
+ ReservedKeyword2["NULL"] = "null";
33
+ ReservedKeyword2["UNDEFINED"] = "undefined";
34
+ ReservedKeyword2["WHILE"] = "while";
35
+ ReservedKeyword2["IF"] = "if";
36
+ ReservedKeyword2["ELSE"] = "else";
37
+ ReservedKeyword2["ELIF"] = "elif";
38
+ ReservedKeyword2["RETURN"] = "return";
39
+ ReservedKeyword2["VARIABLE"] = "variable";
40
+ ReservedKeyword2["FOR"] = "for";
41
+ return ReservedKeyword2;
42
+ })(ReservedKeyword || {});
43
+ var TokenType = /* @__PURE__ */ ((TokenType2) => {
44
+ TokenType2["REFERENCE"] = "REFERENCE";
45
+ TokenType2["NUMBER"] = "NUMBER";
46
+ TokenType2["OPERATION"] = "OPERATION";
47
+ TokenType2["FORMAT"] = "FORMAT";
48
+ TokenType2["LPAREN"] = "LPAREN";
49
+ TokenType2["RPAREN"] = "RPAREN";
50
+ TokenType2["EOF"] = "EOF";
51
+ TokenType2["COMMA"] = "COMMA";
52
+ TokenType2["HEX_COLOR"] = "HEX_COLOR";
53
+ TokenType2["STRING"] = "STRING";
54
+ TokenType2["EXPLICIT_STRING"] = "EXPLICIT_STRING";
55
+ TokenType2["TEMPLATE_STRING"] = "TEMPLATE_STRING";
56
+ TokenType2["ASSIGN"] = "ASSIGN";
57
+ TokenType2["IS_EQ"] = "IS_EQ";
58
+ TokenType2["IS_GT"] = "GT";
59
+ TokenType2["IS_LT"] = "LT";
60
+ TokenType2["IS_GT_EQ"] = "IS_GT_EQ";
61
+ TokenType2["IS_LT_EQ"] = "IS_LT_EQ";
62
+ TokenType2["IS_NOT_EQ"] = "IS_NOT_EQ";
63
+ TokenType2["RESERVED_KEYWORD"] = "RESERVED_KEYWORD";
64
+ TokenType2["SEMICOLON"] = "SEMICOLON";
65
+ TokenType2["LOGIC_NOT"] = "LOGIC_NOT";
66
+ TokenType2["COLON"] = "COLON";
67
+ TokenType2["DOT"] = "DOT";
68
+ TokenType2["LOGIC_AND"] = "LOGIC_AND";
69
+ TokenType2["LOGIC_OR"] = "LOGIC_OR";
70
+ TokenType2["LBLOCK"] = "LBLOCK";
71
+ TokenType2["RBLOCK"] = "RBLOCK";
72
+ TokenType2["PARTIAL_REFERENCE"] = "PARTIAL_REFERENCE";
73
+ TokenType2["PARTIAL_STRING"] = "PARTIAL_STRING";
74
+ return TokenType2;
75
+ })(TokenType || {});
76
+ var UNINTERPRETED_KEYWORDS = [
77
+ "inside",
78
+ "outside",
79
+ "above",
80
+ "below",
81
+ "left",
82
+ "right",
83
+ "top",
84
+ "bottom",
85
+ "before",
86
+ "after",
87
+ "between",
88
+ "uppercase",
89
+ "lowercase",
90
+ "underline",
91
+ "none",
92
+ "innerShadow",
93
+ "outerShadow",
94
+ "shadow"
95
+ ];
96
+
97
+ export { Operations, ReservedKeyword, SupportedFormats, TokenType, UNINTERPRETED_KEYWORDS };
98
+ //# sourceMappingURL=chunk-AXH5N7KV.js.map
99
+ //# sourceMappingURL=chunk-AXH5N7KV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"names":["Operations","SupportedFormats","ReservedKeyword","TokenType"],"mappings":"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","file":"chunk-AXH5N7KV.js","sourcesContent":["import type { Config } from \"@interpreter/config/config\";\n\nexport enum Operations {\n SUBTRACT = \"-\",\n ADD = \"+\",\n MULTIPLY = \"*\",\n DIVIDE = \"/\",\n POWER = \"^\",\n LOGIC_AND = \"&&\",\n LOGIC_OR = \"||\",\n LOGIC_NOT = \"!\",\n}\n\nexport enum SupportedFormats {\n PX = \"px\",\n EM = \"em\",\n REM = \"rem\",\n VW = \"vw\",\n VH = \"vh\",\n PT = \"pt\",\n IN = \"in\",\n CM = \"cm\",\n MM = \"mm\",\n DEG = \"deg\",\n PERCENTAGE = \"%\",\n // Time units\n S = \"s\",\n MS = \"ms\",\n}\n\nexport enum ReservedKeyword {\n TRUE = \"true\",\n FALSE = \"false\",\n NULL = \"null\",\n UNDEFINED = \"undefined\",\n WHILE = \"while\",\n IF = \"if\",\n ELSE = \"else\",\n ELIF = \"elif\",\n RETURN = \"return\",\n VARIABLE = \"variable\",\n FOR = \"for\",\n}\n\nexport enum TokenType {\n REFERENCE = \"REFERENCE\",\n NUMBER = \"NUMBER\",\n OPERATION = \"OPERATION\",\n FORMAT = \"FORMAT\",\n LPAREN = \"LPAREN\",\n RPAREN = \"RPAREN\",\n EOF = \"EOF\",\n COMMA = \"COMMA\",\n HEX_COLOR = \"HEX_COLOR\",\n STRING = \"STRING\",\n EXPLICIT_STRING = \"EXPLICIT_STRING\",\n TEMPLATE_STRING = \"TEMPLATE_STRING\",\n ASSIGN = \"ASSIGN\",\n IS_EQ = \"IS_EQ\",\n IS_GT = \"GT\",\n IS_LT = \"LT\",\n IS_GT_EQ = \"IS_GT_EQ\",\n IS_LT_EQ = \"IS_LT_EQ\",\n IS_NOT_EQ = \"IS_NOT_EQ\",\n RESERVED_KEYWORD = \"RESERVED_KEYWORD\",\n SEMICOLON = \"SEMICOLON\",\n LOGIC_NOT = \"LOGIC_NOT\",\n COLON = \"COLON\",\n DOT = \"DOT\",\n LOGIC_AND = \"LOGIC_AND\",\n LOGIC_OR = \"LOGIC_OR\",\n LBLOCK = \"LBLOCK\",\n RBLOCK = \"RBLOCK\",\n // Partial tokens for tolerant parsing\n PARTIAL_REFERENCE = \"PARTIAL_REFERENCE\",\n PARTIAL_STRING = \"PARTIAL_STRING\",\n}\n\nexport interface Token {\n type: TokenType;\n value: any;\n line: number;\n pos: number;\n endPos: number;\n}\n\nexport interface ASTNode {\n token?: Token;\n nodeType: string;\n}\n\n/**\n * Metadata attached to a symbol that is preserved across cloning operations.\n * This data is not accessible to the tokenscript language itself and is intended\n * for external use (e.g., storing token IDs for tracing).\n */\nexport type SymbolMetadata = Record<string, unknown>;\n\nexport interface ISymbolType {\n type: string;\n value: any;\n\n /**\n * Optional metadata attached to this symbol.\n * This is a reference that is preserved (not cloned) during deepCopy/cloneIfMutable operations.\n * It is not accessible to the tokenscript language and is intended for external use.\n */\n metadata?: SymbolMetadata;\n\n cloneIfMutable(): ISymbolType;\n deepCopy(): ISymbolType;\n\n typeEquals(other: ISymbolType): boolean;\n equals(other: ISymbolType): boolean;\n validValue(value: any): boolean;\n\n toJSON?(): any;\n toString(): string;\n getTypeName(): string;\n toJs(options?: { recursive?: boolean; stringify?: boolean }): any;\n\n hasMethod?(methodName: string, args: ISymbolType[]): boolean;\n callMethod?(methodName: string, args: ISymbolType[]): ISymbolType | null | undefined;\n hasAttribute?(attributeName: string): boolean;\n getAttribute?(attributeName: string): ISymbolType | null;\n setAttribute?(attributeName: string, value: ISymbolType, config?: Config): void;\n}\n\nexport const UNINTERPRETED_KEYWORDS: string[] = [\n \"inside\",\n \"outside\",\n \"above\",\n \"below\",\n \"left\",\n \"right\",\n \"top\",\n \"bottom\",\n \"before\",\n \"after\",\n \"between\",\n \"uppercase\",\n \"lowercase\",\n \"underline\",\n \"none\",\n \"innerShadow\",\n \"outerShadow\",\n \"shadow\",\n];\n\nexport type ReferenceRecordValue = string | number | ISymbolType;\n\nexport type ReferenceRecord = Record<string, ReferenceRecordValue | Array<ReferenceRecordValue>>;\n"]}
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import * as readlineSync from 'readline-sync';
12
12
 
13
13
  // package.json
14
14
  var package_default = {
15
- version: "0.32.0"};
15
+ version: "0.33.0"};
16
16
 
17
17
  // src/types.ts
18
18
  var SupportedFormats = /* @__PURE__ */ ((SupportedFormats2) => {
@@ -151,6 +151,13 @@ var StringNode = class {
151
151
  this.value = token.value;
152
152
  }
153
153
  };
154
+ var TemplateStringNode = class {
155
+ constructor(parts, token) {
156
+ this.parts = parts;
157
+ this.token = token;
158
+ this.nodeType = "TemplateStringNode";
159
+ }
160
+ };
154
161
  var UnaryOpNode = class {
155
162
  constructor(opToken, expr, token) {
156
163
  this.opToken = opToken;
@@ -398,6 +405,10 @@ function walkAST(node, onVisit) {
398
405
  for (const statement of node.statements) {
399
406
  walkAST(statement, onVisit);
400
407
  }
408
+ } else if (node instanceof TemplateStringNode) {
409
+ for (const part of node.parts) {
410
+ walkAST(part, onVisit);
411
+ }
401
412
  } else if (node instanceof AttributeAccessNode) {
402
413
  walkAST(node.left, onVisit);
403
414
  if (node.right instanceof FunctionCallNode || node.right instanceof PartialFunctionCallNode) {
@@ -2548,6 +2559,51 @@ var Lexer = class {
2548
2559
  endPos: this.pos
2549
2560
  };
2550
2561
  }
2562
+ /**
2563
+ * Read a backtick-delimited template string.
2564
+ * Supports escape sequences: \{ \$ \` \\
2565
+ * The raw content (with escapes preserved) is stored as the token value.
2566
+ * The parser handles splitting into segments.
2567
+ */
2568
+ templateString() {
2569
+ const startPos = this.pos;
2570
+ this.eat("`");
2571
+ let result = "";
2572
+ while (this.currentChar !== null && this.currentChar !== "`") {
2573
+ if (this.currentChar === "\\") {
2574
+ const next = this.peek();
2575
+ if (next === "{" || next === "$" || next === "`" || next === "\\") {
2576
+ result += "\\";
2577
+ result += next;
2578
+ this.advance();
2579
+ this.advance();
2580
+ continue;
2581
+ }
2582
+ }
2583
+ result += this.currentChar;
2584
+ this.advance();
2585
+ }
2586
+ if (this.currentChar === null) {
2587
+ if (this.tolerant) {
2588
+ return {
2589
+ type: "TEMPLATE_STRING" /* TEMPLATE_STRING */,
2590
+ value: result,
2591
+ line: this.line,
2592
+ pos: startPos,
2593
+ endPos: this.pos
2594
+ };
2595
+ }
2596
+ this.error("LEXER_UNTERMINATED_TEMPLATE_STRING" /* UNTERMINATED_TEMPLATE_STRING */, {});
2597
+ }
2598
+ this.eat("`");
2599
+ return {
2600
+ type: "TEMPLATE_STRING" /* TEMPLATE_STRING */,
2601
+ value: result,
2602
+ line: this.line,
2603
+ pos: startPos,
2604
+ endPos: this.pos
2605
+ };
2606
+ }
2551
2607
  hexColor() {
2552
2608
  const startPos = this.pos;
2553
2609
  let result = "";
@@ -2598,6 +2654,9 @@ var Lexer = class {
2598
2654
  if (this.currentChar === "'" || this.currentChar === '"') {
2599
2655
  return this.collectToken(this.explicitString(this.currentChar));
2600
2656
  }
2657
+ if (this.currentChar === "`") {
2658
+ return this.collectToken(this.templateString());
2659
+ }
2601
2660
  if (this.isValidIdentifierStart(this.currentChar)) {
2602
2661
  return this.collectToken(this.stringElement());
2603
2662
  }
@@ -2974,7 +3033,7 @@ var Lexer = class {
2974
3033
  };
2975
3034
 
2976
3035
  // src/interpreter/parser.ts
2977
- var Parser = class {
3036
+ var Parser = class _Parser {
2978
3037
  constructor(lexer, options) {
2979
3038
  this.requiredReferences = /* @__PURE__ */ new Set();
2980
3039
  this.incompleteInfo = [];
@@ -3506,6 +3565,9 @@ ${contextText}`;
3506
3565
  node = this.attributeAccess(node);
3507
3566
  return node;
3508
3567
  }
3568
+ if (token.type === "TEMPLATE_STRING" /* TEMPLATE_STRING */) {
3569
+ return this.templateString();
3570
+ }
3509
3571
  if (token.type === "EXPLICIT_STRING" /* EXPLICIT_STRING */) {
3510
3572
  this.eat("EXPLICIT_STRING" /* EXPLICIT_STRING */);
3511
3573
  let node = new StringNode(token);
@@ -3565,6 +3627,122 @@ ${contextText}`;
3565
3627
  this.eat("RPAREN" /* RPAREN */);
3566
3628
  return new FunctionCallNode(functionName.value, args, functionName);
3567
3629
  }
3630
+ /**
3631
+ * Parse a TEMPLATE_STRING token into a TemplateStringNode.
3632
+ * Scans the raw content for:
3633
+ * - {ref.path} → ReferenceNode
3634
+ * - ${expression} → parsed sub-expression
3635
+ * - \{ \${ \` \\ → escaped literals (backslash removed)
3636
+ * - everything else → literal StringNode segments
3637
+ */
3638
+ templateString() {
3639
+ const token = this.currentToken;
3640
+ const raw = token.value;
3641
+ this.eat("TEMPLATE_STRING" /* TEMPLATE_STRING */);
3642
+ const parts = [];
3643
+ let literal = "";
3644
+ let i = 0;
3645
+ const flushLiteral = () => {
3646
+ if (literal.length > 0) {
3647
+ parts.push(new StringNode({ ...token, value: literal }));
3648
+ literal = "";
3649
+ }
3650
+ };
3651
+ while (i < raw.length) {
3652
+ const ch = raw[i];
3653
+ if (ch === "\\" && i + 1 < raw.length) {
3654
+ const next = raw[i + 1];
3655
+ if (next === "{" || next === "`" || next === "\\") {
3656
+ literal += next;
3657
+ i += 2;
3658
+ continue;
3659
+ }
3660
+ if (next === "$") {
3661
+ if (i + 2 < raw.length && raw[i + 2] === "{") {
3662
+ literal += "${";
3663
+ i += 3;
3664
+ } else {
3665
+ literal += "$";
3666
+ i += 2;
3667
+ }
3668
+ continue;
3669
+ }
3670
+ }
3671
+ if (ch === "$" && i + 1 < raw.length && raw[i + 1] === "{") {
3672
+ flushLiteral();
3673
+ const start = i + 2;
3674
+ let depth = 1;
3675
+ let j = start;
3676
+ while (j < raw.length && depth > 0) {
3677
+ if (raw[j] === "`") {
3678
+ this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3679
+ message: "Nested template strings are not allowed inside ${...}"
3680
+ });
3681
+ }
3682
+ if (raw[j] === "{") depth++;
3683
+ else if (raw[j] === "}") depth--;
3684
+ if (depth > 0) j++;
3685
+ }
3686
+ if (depth !== 0) {
3687
+ this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3688
+ message: "Unterminated ${...} in template string"
3689
+ });
3690
+ }
3691
+ const exprStr = raw.slice(start, j);
3692
+ const subLexer = new Lexer(exprStr);
3693
+ const subParser = new _Parser(subLexer);
3694
+ const exprNode = subParser.expr();
3695
+ for (const ref of subParser.requiredReferences) {
3696
+ this.requiredReferences.add(ref);
3697
+ }
3698
+ parts.push(exprNode);
3699
+ i = j + 1;
3700
+ continue;
3701
+ }
3702
+ if (ch === "{") {
3703
+ flushLiteral();
3704
+ const start = i + 1;
3705
+ let j = start;
3706
+ while (j < raw.length && raw[j] !== "}") {
3707
+ if (raw[j] === "{") {
3708
+ this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3709
+ message: "Nested braces in template reference"
3710
+ });
3711
+ }
3712
+ j++;
3713
+ }
3714
+ if (j >= raw.length) {
3715
+ this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3716
+ message: "Unterminated {ref} in template string"
3717
+ });
3718
+ }
3719
+ let refPath = raw.slice(start, j);
3720
+ refPath = refPath.replace(/[ \t]/g, "");
3721
+ if (refPath.length === 0) {
3722
+ this.error("PARSER_INVALID_SYNTAX" /* INVALID_SYNTAX */, {
3723
+ message: "Empty reference in template string"
3724
+ });
3725
+ }
3726
+ this.requiredReferences.add(refPath);
3727
+ parts.push(
3728
+ new ReferenceNode({
3729
+ ...token,
3730
+ type: "REFERENCE" /* REFERENCE */,
3731
+ value: refPath
3732
+ })
3733
+ );
3734
+ i = j + 1;
3735
+ continue;
3736
+ }
3737
+ literal += ch;
3738
+ i++;
3739
+ }
3740
+ flushLiteral();
3741
+ if (parts.length === 1 && parts[0] instanceof StringNode) {
3742
+ return parts[0];
3743
+ }
3744
+ return new TemplateStringNode(parts, token);
3745
+ }
3568
3746
  parse(inlineMode = false) {
3569
3747
  if (this.tolerant && !inlineMode) {
3570
3748
  this.error("PARSER_TOLERANT_REQUIRES_INLINE" /* TOLERANT_REQUIRES_INLINE */);
@@ -8215,6 +8393,47 @@ var Interpreter = class {
8215
8393
  visitStringNode(node) {
8216
8394
  return new StringSymbol(node.value, this.config);
8217
8395
  }
8396
+ visitTemplateStringNode(node) {
8397
+ if (node.parts.length === 0) {
8398
+ return new StringSymbol("", this.config);
8399
+ }
8400
+ if (node.parts.length === 1) {
8401
+ const val = this.visit(node.parts[0]);
8402
+ this.validateTemplateValue(val, node);
8403
+ return val;
8404
+ }
8405
+ let result = "";
8406
+ for (const part of node.parts) {
8407
+ const val = this.visit(part);
8408
+ this.validateTemplateValue(val, node);
8409
+ result += val.toString();
8410
+ }
8411
+ return new StringSymbol(result, this.config);
8412
+ }
8413
+ /**
8414
+ * Validate that a value is a primitive type allowed in template string interpolation.
8415
+ * Lists, Dictionaries, and non-hex Colors are rejected.
8416
+ */
8417
+ validateTemplateValue(val, node) {
8418
+ if (val instanceof ListSymbol) {
8419
+ throw new InterpreterError("INT_TEMPLATE_INVALID_TYPE" /* TEMPLATE_INVALID_TYPE */, {
8420
+ token: node.token,
8421
+ data: { valueType: "List" }
8422
+ });
8423
+ }
8424
+ if (val instanceof DictionarySymbol) {
8425
+ throw new InterpreterError("INT_TEMPLATE_INVALID_TYPE" /* TEMPLATE_INVALID_TYPE */, {
8426
+ token: node.token,
8427
+ data: { valueType: "Dictionary" }
8428
+ });
8429
+ }
8430
+ if (val instanceof ColorSymbol && !val.isHex()) {
8431
+ throw new InterpreterError("INT_TEMPLATE_INVALID_TYPE" /* TEMPLATE_INVALID_TYPE */, {
8432
+ token: node.token,
8433
+ data: { valueType: `Color.${val.subType}` }
8434
+ });
8435
+ }
8436
+ }
8218
8437
  /**
8219
8438
  * Bare identifiers are treated as string literals if not found as variables
8220
8439
  * Check symbol table first (variables override references), then references