@hyperfixi/core 2.1.0 → 2.2.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 (42) hide show
  1. package/dist/api/hyperscript-api.d.ts +6 -1
  2. package/dist/chunks/{bridge-CZfeDyEz.js → bridge-D2DBo02Z.js} +2 -2
  3. package/dist/chunks/browser-modular-BA3JFmkq.js +2 -0
  4. package/dist/chunks/index-C6Fn0jGB.js +2 -0
  5. package/dist/commands/dom/toggle.d.ts +2 -0
  6. package/dist/commands/index.js +35 -0
  7. package/dist/commands/index.mjs +35 -0
  8. package/dist/expressions/index.js +0 -27
  9. package/dist/expressions/index.mjs +0 -27
  10. package/dist/hyperfixi-classic-i18n.js +1 -1
  11. package/dist/hyperfixi-minimal.js +1 -1
  12. package/dist/hyperfixi-multilingual.js +1 -1
  13. package/dist/hyperfixi-standard.js +1 -1
  14. package/dist/hyperfixi.js +1 -1
  15. package/dist/hyperfixi.mjs +1 -1
  16. package/dist/i18n/error-catalog.d.ts +12 -0
  17. package/dist/index.js +31352 -23495
  18. package/dist/index.min.js +1 -1
  19. package/dist/index.mjs +31352 -23495
  20. package/dist/lokascript-browser-classic-i18n.js +1 -1
  21. package/dist/lokascript-browser-minimal.js +1 -1
  22. package/dist/lokascript-browser-standard.js +1 -1
  23. package/dist/lokascript-browser.js +1 -1
  24. package/dist/lokascript-multilingual.js +1 -1
  25. package/dist/lse/index.d.ts +15 -0
  26. package/dist/lse/index.js +84 -0
  27. package/dist/lse/index.mjs +71 -0
  28. package/dist/parser/full-parser.js +596 -240
  29. package/dist/parser/full-parser.mjs +596 -240
  30. package/dist/parser/helpers/ast-helpers.d.ts +1 -0
  31. package/dist/parser/parser-types.d.ts +22 -7
  32. package/dist/parser/parser.d.ts +7 -0
  33. package/dist/parser/pratt-parser.d.ts +42 -0
  34. package/dist/parser/token-consumer.d.ts +1 -2
  35. package/dist/parser/tokenizer.d.ts +0 -33
  36. package/dist/registry/index.js +0 -27
  37. package/dist/registry/index.mjs +0 -27
  38. package/dist/runtime/runtime-base.d.ts +3 -0
  39. package/dist/types/base-types.d.ts +11 -0
  40. package/dist/types/core.d.ts +1 -0
  41. package/package.json +12 -3
  42. package/dist/chunks/browser-modular-CwTpxqdt.js +0 -2
@@ -1,4 +1,4 @@
1
- const KEYWORDS$1 = {
1
+ const KEYWORDS = {
2
2
  THEN: 'then',
3
3
  ELSE: 'else',
4
4
  END: 'end',
@@ -27,11 +27,11 @@ const KEYWORDS$1 = {
27
27
  THE: 'the',
28
28
  START: 'start'};
29
29
  const COMMAND_TERMINATORS = [
30
- KEYWORDS$1.THEN,
31
- KEYWORDS$1.AND,
32
- KEYWORDS$1.ELSE,
33
- KEYWORDS$1.END,
34
- KEYWORDS$1.ON,
30
+ KEYWORDS.THEN,
31
+ KEYWORDS.AND,
32
+ KEYWORDS.ELSE,
33
+ KEYWORDS.END,
34
+ KEYWORDS.ON,
35
35
  ];
36
36
  const COMMANDS = new Set([
37
37
  'add',
@@ -346,74 +346,6 @@ var TokenKind;
346
346
  TokenKind["SYMBOL"] = "symbol";
347
347
  TokenKind["UNKNOWN"] = "unknown";
348
348
  })(TokenKind || (TokenKind = {}));
349
- function getTokenKind(tokenType) {
350
- switch (tokenType) {
351
- case TokenType.KEYWORD:
352
- case TokenType.COMMAND:
353
- case TokenType.EXPRESSION:
354
- case TokenType.CONTEXT_VAR:
355
- case TokenType.GLOBAL_VAR:
356
- case TokenType.EVENT:
357
- case TokenType.IDENTIFIER:
358
- return TokenKind.IDENTIFIER;
359
- case TokenType.STRING:
360
- return TokenKind.STRING;
361
- case TokenType.NUMBER:
362
- return TokenKind.NUMBER;
363
- case TokenType.BOOLEAN:
364
- return TokenKind.IDENTIFIER;
365
- case TokenType.TEMPLATE_LITERAL:
366
- return TokenKind.TEMPLATE;
367
- case TokenType.CSS_SELECTOR:
368
- case TokenType.ID_SELECTOR:
369
- case TokenType.CLASS_SELECTOR:
370
- case TokenType.QUERY_REFERENCE:
371
- return TokenKind.SELECTOR;
372
- case TokenType.OPERATOR:
373
- case TokenType.LOGICAL_OPERATOR:
374
- case TokenType.COMPARISON_OPERATOR:
375
- return TokenKind.OPERATOR;
376
- case TokenType.TIME_EXPRESSION:
377
- return TokenKind.TIME;
378
- case TokenType.COMMENT:
379
- return TokenKind.COMMENT;
380
- case TokenType.SYMBOL:
381
- return TokenKind.SYMBOL;
382
- case TokenType.OBJECT_LITERAL:
383
- case TokenType.ARRAY_LITERAL:
384
- case TokenType.UNKNOWN:
385
- default:
386
- return TokenKind.UNKNOWN;
387
- }
388
- }
389
- var TokenType;
390
- (function (TokenType) {
391
- TokenType["KEYWORD"] = "keyword";
392
- TokenType["COMMAND"] = "command";
393
- TokenType["EXPRESSION"] = "expression";
394
- TokenType["STRING"] = "string";
395
- TokenType["NUMBER"] = "number";
396
- TokenType["BOOLEAN"] = "boolean";
397
- TokenType["TEMPLATE_LITERAL"] = "template_literal";
398
- TokenType["CSS_SELECTOR"] = "css_selector";
399
- TokenType["ID_SELECTOR"] = "id_selector";
400
- TokenType["CLASS_SELECTOR"] = "class_selector";
401
- TokenType["QUERY_REFERENCE"] = "query_reference";
402
- TokenType["CONTEXT_VAR"] = "context_var";
403
- TokenType["GLOBAL_VAR"] = "global_var";
404
- TokenType["EVENT"] = "event";
405
- TokenType["OPERATOR"] = "operator";
406
- TokenType["LOGICAL_OPERATOR"] = "logical_operator";
407
- TokenType["COMPARISON_OPERATOR"] = "comparison_operator";
408
- TokenType["TIME_EXPRESSION"] = "time_expression";
409
- TokenType["OBJECT_LITERAL"] = "object_literal";
410
- TokenType["ARRAY_LITERAL"] = "array_literal";
411
- TokenType["SYMBOL"] = "symbol";
412
- TokenType["COMMENT"] = "comment";
413
- TokenType["IDENTIFIER"] = "identifier";
414
- TokenType["UNKNOWN"] = "unknown";
415
- })(TokenType || (TokenType = {}));
416
- const KEYWORDS = TOKENIZER_KEYWORDS;
417
349
  const MATHEMATICAL_OPERATORS = new Set(['+', '-', '*', '/', 'mod']);
418
350
  const TIME_UNITS = new Set(['ms', 's', 'seconds', 'minutes', 'hours', 'days']);
419
351
  function createTokenizer() {
@@ -456,7 +388,7 @@ function tokenize(input) {
456
388
  const start = tokenizer.position;
457
389
  advance(tokenizer);
458
390
  advance(tokenizer);
459
- addToken(tokenizer, TokenType.OPERATOR, "'s", start);
391
+ addToken(tokenizer, TokenKind.OPERATOR, "'s", start);
460
392
  }
461
393
  else {
462
394
  tokenizeString(tokenizer);
@@ -486,7 +418,7 @@ function tokenize(input) {
486
418
  const start = tokenizer.position;
487
419
  advance(tokenizer);
488
420
  advance(tokenizer);
489
- addToken(tokenizer, TokenType.OPERATOR, '..', start);
421
+ addToken(tokenizer, TokenKind.OPERATOR, '..', start);
490
422
  continue;
491
423
  }
492
424
  const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
@@ -531,46 +463,45 @@ function tokenize(input) {
531
463
  continue;
532
464
  }
533
465
  if (char === '{') {
534
- addToken(tokenizer, TokenType.OPERATOR, '{');
466
+ addToken(tokenizer, TokenKind.OPERATOR, '{');
535
467
  advance(tokenizer);
536
468
  continue;
537
469
  }
538
470
  if (char === '}') {
539
- addToken(tokenizer, TokenType.OPERATOR, '}');
471
+ addToken(tokenizer, TokenKind.OPERATOR, '}');
540
472
  advance(tokenizer);
541
473
  continue;
542
474
  }
543
475
  if (char === '[') {
544
476
  const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
545
477
  const isEventCondition = prevToken &&
546
- (prevToken.kind === TokenType.EVENT ||
547
- (prevToken.kind === TokenType.IDENTIFIER && DOM_EVENTS.has(prevToken.value))) &&
478
+ prevToken.kind === TokenKind.IDENTIFIER &&
479
+ DOM_EVENTS.has(prevToken.value) &&
548
480
  tokenizer.tokens.length >= 2 &&
549
481
  tokenizer.tokens[tokenizer.tokens.length - 2]?.value === 'on';
550
482
  const isMemberAccess = prevToken &&
551
- (prevToken.kind === TokenType.IDENTIFIER ||
552
- prevToken.kind === TokenType.CONTEXT_VAR ||
483
+ (prevToken.kind === TokenKind.IDENTIFIER ||
553
484
  prevToken.value === ')' ||
554
485
  prevToken.value === ']') &&
555
486
  !isEventCondition;
556
487
  if (isMemberAccess) {
557
- addToken(tokenizer, TokenType.OPERATOR, '[');
488
+ addToken(tokenizer, TokenKind.OPERATOR, '[');
558
489
  advance(tokenizer);
559
490
  }
560
491
  else {
561
492
  if (isEventCondition) {
562
- addToken(tokenizer, TokenType.SYMBOL, '[');
493
+ addToken(tokenizer, TokenKind.SYMBOL, '[');
563
494
  advance(tokenizer);
564
495
  }
565
496
  else {
566
- addToken(tokenizer, TokenType.OPERATOR, '[');
497
+ addToken(tokenizer, TokenKind.OPERATOR, '[');
567
498
  advance(tokenizer);
568
499
  }
569
500
  }
570
501
  continue;
571
502
  }
572
503
  if (char === ']') {
573
- addToken(tokenizer, TokenType.OPERATOR, ']');
504
+ addToken(tokenizer, TokenKind.OPERATOR, ']');
574
505
  advance(tokenizer);
575
506
  continue;
576
507
  }
@@ -595,7 +526,7 @@ function tokenize(input) {
595
526
  tokenizeIdentifier(tokenizer);
596
527
  continue;
597
528
  }
598
- addToken(tokenizer, TokenType.UNKNOWN, char);
529
+ addToken(tokenizer, TokenKind.UNKNOWN, char);
599
530
  advance(tokenizer);
600
531
  }
601
532
  return tokenizer.tokens;
@@ -637,7 +568,7 @@ function skipWhitespace(tokenizer) {
637
568
  }
638
569
  }
639
570
  }
640
- function addToken(tokenizer, type, value, start, end) {
571
+ function addToken(tokenizer, kind, value, start, end) {
641
572
  const tokenStart = start ?? tokenizer.position - value.length;
642
573
  const tokenEnd = tokenizer.position;
643
574
  let tokenColumn = tokenizer.column - value.length;
@@ -652,7 +583,7 @@ function addToken(tokenizer, type, value, start, end) {
652
583
  tokenColumn = start - lastNewlinePos;
653
584
  }
654
585
  const token = {
655
- kind: getTokenKind(type),
586
+ kind,
656
587
  value,
657
588
  start: tokenStart,
658
589
  end: tokenEnd,
@@ -688,7 +619,7 @@ function tokenizeComment(tokenizer) {
688
619
  break;
689
620
  value += advance(tokenizer);
690
621
  }
691
- addToken(tokenizer, TokenType.COMMENT, '--' + value, start);
622
+ addToken(tokenizer, TokenKind.COMMENT, '--' + value, start);
692
623
  }
693
624
  function tokenizeString(tokenizer) {
694
625
  const start = tokenizer.position;
@@ -705,7 +636,7 @@ function tokenizeString(tokenizer) {
705
636
  }
706
637
  }
707
638
  }
708
- addToken(tokenizer, TokenType.STRING, value, start);
639
+ addToken(tokenizer, TokenKind.STRING, value, start);
709
640
  }
710
641
  function tokenizeTemplateLiteral(tokenizer) {
711
642
  const start = tokenizer.position;
@@ -749,7 +680,7 @@ function tokenizeTemplateLiteral(tokenizer) {
749
680
  if (tokenizer.position >= tokenizer.input.length && !tokenizer.input.endsWith('`')) {
750
681
  throw new Error(`Unterminated template literal at line ${tokenizer.line}, column ${tokenizer.column - value.length}`);
751
682
  }
752
- addToken(tokenizer, TokenType.TEMPLATE_LITERAL, value, start);
683
+ addToken(tokenizer, TokenKind.TEMPLATE, value, start);
753
684
  }
754
685
  function tokenizeCSSSelector(tokenizer) {
755
686
  const start = tokenizer.position;
@@ -764,8 +695,7 @@ function tokenizeCSSSelector(tokenizer) {
764
695
  break;
765
696
  }
766
697
  }
767
- const type = prefix === '#' ? TokenType.ID_SELECTOR : TokenType.CLASS_SELECTOR;
768
- addToken(tokenizer, type, value, start);
698
+ addToken(tokenizer, TokenKind.SELECTOR, value, start);
769
699
  }
770
700
  function tokenizeQueryReference(tokenizer) {
771
701
  const start = tokenizer.position;
@@ -780,7 +710,7 @@ function tokenizeQueryReference(tokenizer) {
780
710
  break;
781
711
  }
782
712
  }
783
- addToken(tokenizer, TokenType.QUERY_REFERENCE, value, start);
713
+ addToken(tokenizer, TokenKind.SELECTOR, value, start);
784
714
  }
785
715
  function tokenizeSymbol(tokenizer) {
786
716
  const start = tokenizer.position;
@@ -794,7 +724,7 @@ function tokenizeSymbol(tokenizer) {
794
724
  break;
795
725
  }
796
726
  }
797
- addToken(tokenizer, TokenType.SYMBOL, value, start);
727
+ addToken(tokenizer, TokenKind.SYMBOL, value, start);
798
728
  }
799
729
  function tokenizeOperator(tokenizer) {
800
730
  const start = tokenizer.position;
@@ -804,7 +734,7 @@ function tokenizeOperator(tokenizer) {
804
734
  value = "'s";
805
735
  advance(tokenizer);
806
736
  advance(tokenizer);
807
- addToken(tokenizer, TokenType.OPERATOR, value, start);
737
+ addToken(tokenizer, TokenKind.OPERATOR, value, start);
808
738
  return;
809
739
  }
810
740
  const twoChar = tokenizer.input.substring(tokenizer.position, tokenizer.position + 2);
@@ -823,17 +753,7 @@ function tokenizeOperator(tokenizer) {
823
753
  else {
824
754
  value = advance(tokenizer);
825
755
  }
826
- let type = TokenType.OPERATOR;
827
- if (COMPARISON_OPERATORS.has(value)) {
828
- type = TokenType.COMPARISON_OPERATOR;
829
- }
830
- else if (['&&', '||'].includes(value)) {
831
- type = TokenType.LOGICAL_OPERATOR;
832
- }
833
- else if (MATHEMATICAL_OPERATORS.has(value)) {
834
- type = TokenType.OPERATOR;
835
- }
836
- addToken(tokenizer, type, value, start);
756
+ addToken(tokenizer, TokenKind.OPERATOR, value, start);
837
757
  }
838
758
  function tokenizeNumberOrTime(tokenizer) {
839
759
  const start = tokenizer.position;
@@ -899,11 +819,11 @@ function tokenizeNumberOrTime(tokenizer) {
899
819
  }
900
820
  }
901
821
  if (TIME_UNITS.has(unit)) {
902
- addToken(tokenizer, TokenType.TIME_EXPRESSION, value + unit, start);
822
+ addToken(tokenizer, TokenKind.TIME, value + unit, start);
903
823
  }
904
824
  else {
905
825
  tokenizer.position = unitStart;
906
- addToken(tokenizer, TokenType.NUMBER, value, start);
826
+ addToken(tokenizer, TokenKind.NUMBER, value, start);
907
827
  }
908
828
  }
909
829
  function tokenizeIdentifier(tokenizer) {
@@ -949,7 +869,7 @@ function tokenizeGlobalVariable(tokenizer) {
949
869
  break;
950
870
  }
951
871
  }
952
- addToken(tokenizer, TokenType.GLOBAL_VAR, value, start);
872
+ addToken(tokenizer, TokenKind.IDENTIFIER, value, start);
953
873
  }
954
874
  function tryTokenizeCompoundOperator(tokenizer, firstWord, start) {
955
875
  const lowerFirst = firstWord.toLowerCase();
@@ -959,10 +879,7 @@ function tryTokenizeCompoundOperator(tokenizer, firstWord, start) {
959
879
  }
960
880
  const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
961
881
  if (prevToken &&
962
- (prevToken.kind === 'identifier' ||
963
- prevToken.kind === 'id_selector' ||
964
- prevToken.kind === 'class_selector' ||
965
- prevToken.kind === 'context_var')) {
882
+ (prevToken.kind === TokenKind.IDENTIFIER || prevToken.kind === TokenKind.SELECTOR)) {
966
883
  const nextChar = tokenizer.position < tokenizer.input.length ? tokenizer.input[tokenizer.position] : '';
967
884
  if (nextChar === "'" || nextChar === "'") {
968
885
  return false;
@@ -992,17 +909,17 @@ function tryTokenizeCompoundOperator(tokenizer, firstWord, start) {
992
909
  }
993
910
  const longestCompound = tryBuildLongestCompound(tokenizer, lowerFirst, lowerNext);
994
911
  if (longestCompound) {
995
- addToken(tokenizer, TokenType.COMPARISON_OPERATOR, longestCompound, start);
912
+ addToken(tokenizer, TokenKind.OPERATOR, longestCompound, start);
996
913
  return true;
997
914
  }
998
915
  if (COMPARISON_OPERATORS.has(compound)) {
999
- addToken(tokenizer, TokenType.COMPARISON_OPERATOR, compound, start);
916
+ addToken(tokenizer, TokenKind.OPERATOR, compound, start);
1000
917
  return true;
1001
918
  }
1002
919
  }
1003
920
  if (COMPARISON_OPERATORS.has(lowerFirst)) {
1004
921
  tokenizer.position = originalPosition;
1005
- addToken(tokenizer, TokenType.COMPARISON_OPERATOR, firstWord, start);
922
+ addToken(tokenizer, TokenKind.OPERATOR, firstWord, start);
1006
923
  return true;
1007
924
  }
1008
925
  tokenizer.position = originalPosition;
@@ -1049,7 +966,7 @@ function tryBuildCompoundPreposition(tokenizer, firstWord, secondWord, start) {
1049
966
  const lowerFourth = fourthWord.toLowerCase();
1050
967
  if (lowerFourth === 'of') {
1051
968
  const compound = `at the ${lowerThird} of`;
1052
- addToken(tokenizer, TokenType.KEYWORD, compound, start);
969
+ addToken(tokenizer, TokenKind.IDENTIFIER, compound, start);
1053
970
  return true;
1054
971
  }
1055
972
  }
@@ -1075,7 +992,7 @@ function tryBuildCompoundPreposition(tokenizer, firstWord, secondWord, start) {
1075
992
  const lowerThird = thirdWord.toLowerCase();
1076
993
  if (lowerThird === 'of') {
1077
994
  const compound = `at ${lowerSecond} of`;
1078
- addToken(tokenizer, TokenType.KEYWORD, compound, start);
995
+ addToken(tokenizer, TokenKind.IDENTIFIER, compound, start);
1079
996
  return true;
1080
997
  }
1081
998
  tokenizer.position = afterSecondWord;
@@ -1087,36 +1004,18 @@ function tryBuildCompoundPreposition(tokenizer, firstWord, secondWord, start) {
1087
1004
  function classifyIdentifier(value) {
1088
1005
  const lowerValue = value.toLowerCase();
1089
1006
  if (lowerValue === 'include' || lowerValue === 'includes') {
1090
- return TokenType.COMPARISON_OPERATOR;
1007
+ return TokenKind.OPERATOR;
1091
1008
  }
1092
1009
  if (LOGICAL_OPERATORS.has(lowerValue)) {
1093
- return TokenType.LOGICAL_OPERATOR;
1010
+ return TokenKind.OPERATOR;
1094
1011
  }
1095
1012
  if (MATHEMATICAL_OPERATORS.has(value) || MATHEMATICAL_OPERATORS.has(lowerValue)) {
1096
- return TokenType.OPERATOR;
1013
+ return TokenKind.OPERATOR;
1097
1014
  }
1098
1015
  if (COMPARISON_OPERATORS.has(lowerValue)) {
1099
- return TokenType.COMPARISON_OPERATOR;
1016
+ return TokenKind.OPERATOR;
1100
1017
  }
1101
- if (value === 'I') {
1102
- return TokenType.CONTEXT_VAR;
1103
- }
1104
- if (CONTEXT_VARS.has(lowerValue)) {
1105
- return TokenType.CONTEXT_VAR;
1106
- }
1107
- if (COMMANDS.has(lowerValue)) {
1108
- return TokenType.COMMAND;
1109
- }
1110
- if (DOM_EVENTS.has(lowerValue)) {
1111
- return TokenType.EVENT;
1112
- }
1113
- if (['true', 'false', 'null', 'undefined'].includes(lowerValue)) {
1114
- return TokenType.BOOLEAN;
1115
- }
1116
- if (KEYWORDS.has(lowerValue)) {
1117
- return TokenType.KEYWORD;
1118
- }
1119
- return TokenType.IDENTIFIER;
1018
+ return TokenKind.IDENTIFIER;
1120
1019
  }
1121
1020
  function isAlpha(char) {
1122
1021
  return /[a-zA-Z]/.test(char);
@@ -1382,6 +1281,9 @@ class SemanticIntegrationAdapter {
1382
1281
  if (/\btell\b/.test(lowerInput)) {
1383
1282
  return true;
1384
1283
  }
1284
+ if (/\*[a-zA-Z]/.test(input)) {
1285
+ return true;
1286
+ }
1385
1287
  return false;
1386
1288
  }
1387
1289
  trySemanticParse(input) {
@@ -2132,6 +2034,26 @@ function createErrorNode(pos) {
2132
2034
  column: pos.column,
2133
2035
  };
2134
2036
  }
2037
+ function createErrorCommandNode(pos, message, source) {
2038
+ const diagnostic = {
2039
+ message,
2040
+ severity: 'error',
2041
+ code: 'parse-error',
2042
+ line: pos.line,
2043
+ column: pos.column,
2044
+ ...(source && { source }),
2045
+ };
2046
+ return {
2047
+ type: 'command',
2048
+ name: '__ERROR__',
2049
+ args: [],
2050
+ diagnostics: [diagnostic],
2051
+ start: pos.start,
2052
+ end: pos.end,
2053
+ line: pos.line,
2054
+ column: pos.column,
2055
+ };
2056
+ }
2135
2057
  function createProgramNode(statements) {
2136
2058
  debug.parse(`✅ createProgramNode: Called with ${statements.length} statements`);
2137
2059
  if (statements.length === 0) {
@@ -2176,10 +2098,10 @@ function isKeyword(token, keywords) {
2176
2098
  return keywords.some(kw => token.value === kw || token.value.toLowerCase() === kw);
2177
2099
  }
2178
2100
  const DEFAULT_BOUNDARY_KEYWORDS = [
2179
- KEYWORDS$1.THEN,
2180
- KEYWORDS$1.AND,
2181
- KEYWORDS$1.ELSE,
2182
- KEYWORDS$1.END,
2101
+ KEYWORDS.THEN,
2102
+ KEYWORDS.AND,
2103
+ KEYWORDS.ELSE,
2104
+ KEYWORDS.END,
2183
2105
  ];
2184
2106
  function isCommandBoundary(ctx, additionalBoundaries = []) {
2185
2107
  if (ctx.isAtEnd()) {
@@ -2489,21 +2411,21 @@ function parseTriggerCommand(ctx, identifierNode) {
2489
2411
 
2490
2412
  function parseHaltCommand(ctx, identifierNode) {
2491
2413
  const args = [];
2492
- if (ctx.check(KEYWORDS$1.THE)) {
2414
+ if (ctx.check(KEYWORDS.THE)) {
2493
2415
  const theToken = ctx.advance();
2494
2416
  args.push({
2495
2417
  type: 'identifier',
2496
- name: KEYWORDS$1.THE,
2418
+ name: KEYWORDS.THE,
2497
2419
  start: theToken.start,
2498
2420
  end: theToken.end,
2499
2421
  line: theToken.line,
2500
2422
  column: theToken.column,
2501
2423
  });
2502
- if (ctx.check(KEYWORDS$1.EVENT)) {
2424
+ if (ctx.check(KEYWORDS.EVENT)) {
2503
2425
  const eventToken = ctx.advance();
2504
2426
  args.push({
2505
2427
  type: 'identifier',
2506
- name: KEYWORDS$1.EVENT,
2428
+ name: KEYWORDS.EVENT,
2507
2429
  start: eventToken.start,
2508
2430
  end: eventToken.end,
2509
2431
  line: eventToken.line,
@@ -2525,34 +2447,34 @@ function parseRepeatCommand(ctx, commandToken) {
2525
2447
  let collection = null;
2526
2448
  let variable = null;
2527
2449
  let times = null;
2528
- if (ctx.check(KEYWORDS$1.FOR)) {
2450
+ if (ctx.check(KEYWORDS.FOR)) {
2529
2451
  ctx.advance();
2530
- loopType = KEYWORDS$1.FOR;
2452
+ loopType = KEYWORDS.FOR;
2531
2453
  const identToken = ctx.peek();
2532
2454
  if (isIdentifierLike(identToken)) {
2533
2455
  variable = identToken.value;
2534
2456
  ctx.advance();
2535
2457
  }
2536
- if (ctx.check(KEYWORDS$1.IN)) {
2458
+ if (ctx.check(KEYWORDS.IN)) {
2537
2459
  ctx.advance();
2538
2460
  collection = ctx.parseExpression();
2539
2461
  }
2540
2462
  }
2541
- else if (ctx.check(KEYWORDS$1.IN)) {
2463
+ else if (ctx.check(KEYWORDS.IN)) {
2542
2464
  ctx.advance();
2543
- loopType = KEYWORDS$1.FOR;
2465
+ loopType = KEYWORDS.FOR;
2544
2466
  variable = 'it';
2545
2467
  collection = ctx.parseExpression();
2546
2468
  }
2547
- else if (ctx.check(KEYWORDS$1.WHILE)) {
2469
+ else if (ctx.check(KEYWORDS.WHILE)) {
2548
2470
  ctx.advance();
2549
- loopType = KEYWORDS$1.WHILE;
2471
+ loopType = KEYWORDS.WHILE;
2550
2472
  condition = ctx.parseExpression();
2551
2473
  }
2552
- else if (ctx.check(KEYWORDS$1.UNTIL)) {
2474
+ else if (ctx.check(KEYWORDS.UNTIL)) {
2553
2475
  ctx.advance();
2554
- loopType = KEYWORDS$1.UNTIL;
2555
- if (ctx.check(KEYWORDS$1.EVENT)) {
2476
+ loopType = KEYWORDS.UNTIL;
2477
+ if (ctx.check(KEYWORDS.EVENT)) {
2556
2478
  ctx.advance();
2557
2479
  loopType = 'until-event';
2558
2480
  const eventToken = ctx.peek();
@@ -2569,11 +2491,11 @@ function parseRepeatCommand(ctx, commandToken) {
2569
2491
  throw new Error('Expected event name after "event"');
2570
2492
  }
2571
2493
  debug.parse('🔍 Checking for "from", current token:', ctx.peek().value);
2572
- if (ctx.check(KEYWORDS$1.FROM)) {
2494
+ if (ctx.check(KEYWORDS.FROM)) {
2573
2495
  debug.parse('✅ Found "from", advancing...');
2574
2496
  ctx.advance();
2575
2497
  debug.parse('📍 After consuming "from", current token:', ctx.peek().value);
2576
- if (consumeOptionalKeyword(ctx, KEYWORDS$1.THE)) {
2498
+ if (consumeOptionalKeyword(ctx, KEYWORDS.THE)) {
2577
2499
  debug.parse('✅ Found "the", advancing...');
2578
2500
  }
2579
2501
  const beforePrimary = ctx.peek();
@@ -2593,27 +2515,27 @@ function parseRepeatCommand(ctx, commandToken) {
2593
2515
  condition = ctx.parseExpression();
2594
2516
  }
2595
2517
  }
2596
- else if (ctx.check(KEYWORDS$1.FOREVER)) {
2518
+ else if (ctx.check(KEYWORDS.FOREVER)) {
2597
2519
  ctx.advance();
2598
- loopType = KEYWORDS$1.FOREVER;
2520
+ loopType = KEYWORDS.FOREVER;
2599
2521
  }
2600
2522
  else {
2601
2523
  times = ctx.parseExpression();
2602
- if (ctx.check(KEYWORDS$1.TIMES)) {
2524
+ if (ctx.check(KEYWORDS.TIMES)) {
2603
2525
  ctx.advance();
2604
- loopType = KEYWORDS$1.TIMES;
2526
+ loopType = KEYWORDS.TIMES;
2605
2527
  }
2606
2528
  }
2607
2529
  let indexVariable = null;
2608
- if (ctx.check(KEYWORDS$1.WITH)) {
2530
+ if (ctx.check(KEYWORDS.WITH)) {
2609
2531
  const nextToken = ctx.peekAt(1);
2610
- if (nextToken && nextToken.value.toLowerCase() === KEYWORDS$1.INDEX) {
2532
+ if (nextToken && nextToken.value.toLowerCase() === KEYWORDS.INDEX) {
2611
2533
  ctx.advance();
2612
2534
  ctx.advance();
2613
- indexVariable = KEYWORDS$1.INDEX;
2535
+ indexVariable = KEYWORDS.INDEX;
2614
2536
  }
2615
2537
  }
2616
- else if (ctx.check(KEYWORDS$1.INDEX)) {
2538
+ else if (ctx.check(KEYWORDS.INDEX)) {
2617
2539
  ctx.advance();
2618
2540
  const indexToken = ctx.peek();
2619
2541
  if (isIdentifierLike(indexToken)) {
@@ -2621,7 +2543,7 @@ function parseRepeatCommand(ctx, commandToken) {
2621
2543
  ctx.advance();
2622
2544
  }
2623
2545
  else {
2624
- indexVariable = KEYWORDS$1.INDEX;
2546
+ indexVariable = KEYWORDS.INDEX;
2625
2547
  }
2626
2548
  }
2627
2549
  const commands = ctx.parseCommandListUntilEnd();
@@ -2669,14 +2591,14 @@ function parseIfCommand(ctx, commandToken) {
2669
2591
  const maxThenLookahead = 500;
2670
2592
  for (let i = 0; i < maxThenLookahead && !ctx.isAtEnd(); i++) {
2671
2593
  const token = ctx.peek();
2672
- if (token.value === KEYWORDS$1.THEN) {
2594
+ if (token.value === KEYWORDS.THEN) {
2673
2595
  hasThen = true;
2674
2596
  break;
2675
2597
  }
2676
- if (token.value === KEYWORDS$1.END ||
2677
- token.value === KEYWORDS$1.BEHAVIOR ||
2678
- token.value === KEYWORDS$1.DEF ||
2679
- token.value === KEYWORDS$1.ON) {
2598
+ if (token.value === KEYWORDS.END ||
2599
+ token.value === KEYWORDS.BEHAVIOR ||
2600
+ token.value === KEYWORDS.DEF ||
2601
+ token.value === KEYWORDS.ON) {
2680
2602
  break;
2681
2603
  }
2682
2604
  ctx.advance();
@@ -2690,12 +2612,12 @@ function parseIfCommand(ctx, commandToken) {
2690
2612
  while (!ctx.isAtEnd() && ctx.current - savedPosition < maxLookahead) {
2691
2613
  const token = ctx.peek();
2692
2614
  const tokenValue = token.value?.toLowerCase();
2693
- if (tokenValue === KEYWORDS$1.BEHAVIOR ||
2694
- tokenValue === KEYWORDS$1.DEF ||
2695
- tokenValue === KEYWORDS$1.ON) {
2615
+ if (tokenValue === KEYWORDS.BEHAVIOR ||
2616
+ tokenValue === KEYWORDS.DEF ||
2617
+ tokenValue === KEYWORDS.ON) {
2696
2618
  break;
2697
2619
  }
2698
- if (tokenValue === KEYWORDS$1.ELSE || tokenValue === KEYWORDS$1.END) {
2620
+ if (tokenValue === KEYWORDS.ELSE || tokenValue === KEYWORDS.END) {
2699
2621
  if (token.line === ifStatementLine) {
2700
2622
  hasImplicitMultiLineEnd = true;
2701
2623
  }
@@ -2723,7 +2645,7 @@ function parseIfCommand(ctx, commandToken) {
2723
2645
  while (!ctx.isAtEnd() &&
2724
2646
  !ctx.checkIsCommand() &&
2725
2647
  !ctx.isCommand(ctx.peek().value) &&
2726
- !ctx.check(KEYWORDS$1.THEN) &&
2648
+ !ctx.check(KEYWORDS.THEN) &&
2727
2649
  iterations < maxIterations) {
2728
2650
  const beforePos = ctx.savePosition();
2729
2651
  conditionTokens.push(ctx.parseLogicalAnd());
@@ -2755,7 +2677,7 @@ function parseIfCommand(ctx, commandToken) {
2755
2677
  ctx.advance();
2756
2678
  }
2757
2679
  const thenCommands = [];
2758
- while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.ELSE) && !ctx.check(KEYWORDS$1.END)) {
2680
+ while (!ctx.isAtEnd() && !ctx.check(KEYWORDS.ELSE) && !ctx.check(KEYWORDS.END)) {
2759
2681
  if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
2760
2682
  ctx.advance();
2761
2683
  const cmd = ctx.parseCommand();
@@ -2777,9 +2699,9 @@ function parseIfCommand(ctx, commandToken) {
2777
2699
  column: commandToken.column,
2778
2700
  }));
2779
2701
  let consumedElseIf = false;
2780
- if (ctx.check(KEYWORDS$1.ELSE)) {
2702
+ if (ctx.check(KEYWORDS.ELSE)) {
2781
2703
  ctx.advance();
2782
- if (ctx.check(KEYWORDS$1.IF)) {
2704
+ if (ctx.check(KEYWORDS.IF)) {
2783
2705
  const ifToken = ctx.peek();
2784
2706
  ctx.advance();
2785
2707
  const elseIfCommand = parseIfCommand(ctx, ifToken);
@@ -2793,7 +2715,7 @@ function parseIfCommand(ctx, commandToken) {
2793
2715
  }
2794
2716
  else {
2795
2717
  const elseCommands = [];
2796
- while (!ctx.isAtEnd() && !ctx.check(KEYWORDS$1.END)) {
2718
+ while (!ctx.isAtEnd() && !ctx.check(KEYWORDS.END)) {
2797
2719
  if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
2798
2720
  ctx.advance();
2799
2721
  const cmd = ctx.parseCommand();
@@ -2814,7 +2736,7 @@ function parseIfCommand(ctx, commandToken) {
2814
2736
  }
2815
2737
  }
2816
2738
  if (!consumedElseIf) {
2817
- ctx.consume(KEYWORDS$1.END, "Expected 'end' after if block");
2739
+ ctx.consume(KEYWORDS.END, "Expected 'end' after if block");
2818
2740
  }
2819
2741
  }
2820
2742
  else {
@@ -2841,7 +2763,7 @@ function parseForCommand(ctx, commandToken) {
2841
2763
  const args = [];
2842
2764
  let variable = null;
2843
2765
  let collection = null;
2844
- if (ctx.check(KEYWORDS$1.EACH)) {
2766
+ if (ctx.check(KEYWORDS.EACH)) {
2845
2767
  ctx.advance();
2846
2768
  }
2847
2769
  const identToken = ctx.peek();
@@ -2852,7 +2774,7 @@ function parseForCommand(ctx, commandToken) {
2852
2774
  else {
2853
2775
  throw new Error('Expected variable name after "for"');
2854
2776
  }
2855
- if (!ctx.check(KEYWORDS$1.IN)) {
2777
+ if (!ctx.check(KEYWORDS.IN)) {
2856
2778
  throw new Error('Expected "in" after variable name in for loop');
2857
2779
  }
2858
2780
  ctx.advance();
@@ -2861,15 +2783,15 @@ function parseForCommand(ctx, commandToken) {
2861
2783
  throw new Error('Expected collection expression after "in"');
2862
2784
  }
2863
2785
  let indexVariable = null;
2864
- if (ctx.check(KEYWORDS$1.WITH)) {
2786
+ if (ctx.check(KEYWORDS.WITH)) {
2865
2787
  const nextToken = ctx.peekAt(1);
2866
- if (nextToken && nextToken.value.toLowerCase() === KEYWORDS$1.INDEX) {
2788
+ if (nextToken && nextToken.value.toLowerCase() === KEYWORDS.INDEX) {
2867
2789
  ctx.advance();
2868
2790
  ctx.advance();
2869
- indexVariable = KEYWORDS$1.INDEX;
2791
+ indexVariable = KEYWORDS.INDEX;
2870
2792
  }
2871
2793
  }
2872
- else if (ctx.check(KEYWORDS$1.INDEX)) {
2794
+ else if (ctx.check(KEYWORDS.INDEX)) {
2873
2795
  ctx.advance();
2874
2796
  const indexToken = ctx.peek();
2875
2797
  if (isIdentifierLike(indexToken)) {
@@ -2877,7 +2799,7 @@ function parseForCommand(ctx, commandToken) {
2877
2799
  ctx.advance();
2878
2800
  }
2879
2801
  else {
2880
- indexVariable = KEYWORDS$1.INDEX;
2802
+ indexVariable = KEYWORDS.INDEX;
2881
2803
  }
2882
2804
  }
2883
2805
  const commands = ctx.parseCommandListUntilEnd();
@@ -2989,7 +2911,7 @@ function parseTransitionCommand(ctx, commandToken) {
2989
2911
  throw new Error('Transition command requires a CSS property');
2990
2912
  }
2991
2913
  args.push(property);
2992
- if (!ctx.check(KEYWORDS$1.TO)) {
2914
+ if (!ctx.check(KEYWORDS.TO)) {
2993
2915
  throw new Error('Expected "to" keyword after property in transition command');
2994
2916
  }
2995
2917
  ctx.advance();
@@ -3000,7 +2922,7 @@ function parseTransitionCommand(ctx, commandToken) {
3000
2922
  const duration = ctx.parsePrimary();
3001
2923
  modifiers['over'] = duration;
3002
2924
  }
3003
- if (ctx.check(KEYWORDS$1.WITH)) {
2925
+ if (ctx.check(KEYWORDS.WITH)) {
3004
2926
  ctx.advance();
3005
2927
  const timingFunction = ctx.parsePrimary();
3006
2928
  modifiers['with'] = timingFunction;
@@ -3014,11 +2936,11 @@ function parseTransitionCommand(ctx, commandToken) {
3014
2936
 
3015
2937
  function parseRemoveCommand(ctx, identifierNode) {
3016
2938
  const args = [];
3017
- const classArg = parseOneArgument(ctx, [KEYWORDS$1.FROM]);
2939
+ const classArg = parseOneArgument(ctx, [KEYWORDS.FROM]);
3018
2940
  if (classArg) {
3019
2941
  args.push(classArg);
3020
2942
  }
3021
- consumeKeywordToArgs(ctx, KEYWORDS$1.FROM, args);
2943
+ consumeKeywordToArgs(ctx, KEYWORDS.FROM, args);
3022
2944
  const targetArg = parseOneArgument(ctx);
3023
2945
  if (targetArg) {
3024
2946
  args.push(targetArg);
@@ -3030,19 +2952,19 @@ function parseRemoveCommand(ctx, identifierNode) {
3030
2952
  }
3031
2953
  function parseToggleCommand(ctx, identifierNode) {
3032
2954
  const args = [];
3033
- if (ctx.check(KEYWORDS$1.BETWEEN)) {
2955
+ if (ctx.check(KEYWORDS.BETWEEN)) {
3034
2956
  ctx.advance();
3035
2957
  args.push(ctx.createIdentifier('between'));
3036
- const firstArg = parseOneArgument(ctx, [KEYWORDS$1.AND]);
2958
+ const firstArg = parseOneArgument(ctx, [KEYWORDS.AND]);
3037
2959
  if (firstArg) {
3038
2960
  args.push(firstArg);
3039
2961
  }
3040
- consumeKeywordToArgs(ctx, KEYWORDS$1.AND, args);
3041
- const secondArg = parseOneArgument(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON, KEYWORDS$1.FOR]);
2962
+ consumeKeywordToArgs(ctx, KEYWORDS.AND, args);
2963
+ const secondArg = parseOneArgument(ctx, [KEYWORDS.FROM, KEYWORDS.ON, KEYWORDS.FOR]);
3042
2964
  if (secondArg) {
3043
2965
  args.push(secondArg);
3044
2966
  }
3045
- const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON], args);
2967
+ const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS.FROM, KEYWORDS.ON], args);
3046
2968
  if (preposition) {
3047
2969
  const targetArg = parseOneArgument(ctx);
3048
2970
  if (targetArg) {
@@ -3054,11 +2976,11 @@ function parseToggleCommand(ctx, identifierNode) {
3054
2976
  .endingAt(ctx.getPosition())
3055
2977
  .build();
3056
2978
  }
3057
- const classArg = parseOneArgument(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON]);
2979
+ const classArg = parseOneArgument(ctx, [KEYWORDS.FROM, KEYWORDS.ON]);
3058
2980
  if (classArg) {
3059
2981
  args.push(classArg);
3060
2982
  }
3061
- const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS$1.FROM, KEYWORDS$1.ON], args);
2983
+ const preposition = consumeOneOfKeywordsToArgs(ctx, [KEYWORDS.FROM, KEYWORDS.ON], args);
3062
2984
  if (preposition) {
3063
2985
  const targetArg = parseOneArgument(ctx);
3064
2986
  if (targetArg) {
@@ -3076,12 +2998,12 @@ function parseAddCommand(ctx, commandToken) {
3076
2998
  args.push(ctx.parseCSSObjectLiteral());
3077
2999
  }
3078
3000
  else {
3079
- const classArg = parseOneArgument(ctx, [KEYWORDS$1.TO]);
3001
+ const classArg = parseOneArgument(ctx, [KEYWORDS.TO]);
3080
3002
  if (classArg) {
3081
3003
  args.push(classArg);
3082
3004
  }
3083
3005
  }
3084
- if (ctx.check(KEYWORDS$1.TO)) {
3006
+ if (ctx.check(KEYWORDS.TO)) {
3085
3007
  ctx.advance();
3086
3008
  const targetArg = parseOneArgument(ctx);
3087
3009
  if (targetArg) {
@@ -3114,19 +3036,19 @@ function parsePutCommand(ctx, identifierNode) {
3114
3036
  operation = PUT_OPERATIONS.AT_END_OF;
3115
3037
  }
3116
3038
  else if (operation === PUT_OPERATIONS.AT) {
3117
- if (ctx.check(KEYWORDS$1.START) || ctx.check(KEYWORDS$1.THE)) {
3118
- consumeOptionalKeyword(ctx, KEYWORDS$1.THE);
3119
- if (ctx.check(KEYWORDS$1.START)) {
3039
+ if (ctx.check(KEYWORDS.START) || ctx.check(KEYWORDS.THE)) {
3040
+ consumeOptionalKeyword(ctx, KEYWORDS.THE);
3041
+ if (ctx.check(KEYWORDS.START)) {
3120
3042
  ctx.advance();
3121
- if (ctx.check(KEYWORDS$1.OF)) {
3043
+ if (ctx.check(KEYWORDS.OF)) {
3122
3044
  ctx.advance();
3123
3045
  operation = PUT_OPERATIONS.AT_START_OF;
3124
3046
  }
3125
3047
  }
3126
3048
  }
3127
- else if (ctx.check(KEYWORDS$1.END)) {
3049
+ else if (ctx.check(KEYWORDS.END)) {
3128
3050
  ctx.advance();
3129
- if (ctx.check(KEYWORDS$1.OF)) {
3051
+ if (ctx.check(KEYWORDS.OF)) {
3130
3052
  ctx.advance();
3131
3053
  operation = PUT_OPERATIONS.AT_END_OF;
3132
3054
  }
@@ -3176,7 +3098,7 @@ function parseSwapCommand(ctx, identifierNode) {
3176
3098
  .endingAt(ctx.getPosition())
3177
3099
  .build();
3178
3100
  }
3179
- if (!ctx.isAtEnd() && ctx.check(KEYWORDS$1.OF)) {
3101
+ if (!ctx.isAtEnd() && ctx.check(KEYWORDS.OF)) {
3180
3102
  ctx.advance();
3181
3103
  args.push(ctx.createIdentifier('of'));
3182
3104
  }
@@ -3184,7 +3106,7 @@ function parseSwapCommand(ctx, identifierNode) {
3184
3106
  if (targetExpr) {
3185
3107
  args.push(targetExpr);
3186
3108
  }
3187
- if (!ctx.isAtEnd() && ctx.check(KEYWORDS$1.WITH)) {
3109
+ if (!ctx.isAtEnd() && ctx.check(KEYWORDS.WITH)) {
3188
3110
  ctx.advance();
3189
3111
  args.push(ctx.createIdentifier('with'));
3190
3112
  const contentExpr = ctx.parseExpression();
@@ -3250,9 +3172,9 @@ function parseWaitCommand(ctx, commandToken) {
3250
3172
  }
3251
3173
  } while (!ctx.isAtEnd());
3252
3174
  let eventTarget = null;
3253
- if (ctx.check(KEYWORDS$1.FROM)) {
3175
+ if (ctx.check(KEYWORDS.FROM)) {
3254
3176
  ctx.advance();
3255
- consumeOptionalKeyword(ctx, KEYWORDS$1.THE);
3177
+ consumeOptionalKeyword(ctx, KEYWORDS.THE);
3256
3178
  eventTarget = ctx.parsePrimary();
3257
3179
  }
3258
3180
  const eventPos = {
@@ -3370,7 +3292,7 @@ function parseColonVariable(ctx) {
3370
3292
  };
3371
3293
  }
3372
3294
  function parseScopedVariable(ctx) {
3373
- if (!ctx.check(KEYWORDS$1.GLOBAL) && !ctx.check(KEYWORDS$1.LOCAL))
3295
+ if (!ctx.check(KEYWORDS.GLOBAL) && !ctx.check(KEYWORDS.LOCAL))
3374
3296
  return null;
3375
3297
  const scopeToken = ctx.advance();
3376
3298
  const variableToken = ctx.advance();
@@ -3383,15 +3305,15 @@ function parseScopedVariable(ctx) {
3383
3305
  };
3384
3306
  }
3385
3307
  function parsePropertyOfTarget(ctx, startPosition) {
3386
- if (!ctx.check(KEYWORDS$1.THE))
3308
+ if (!ctx.check(KEYWORDS.THE))
3387
3309
  return null;
3388
3310
  const thePosition = ctx.savePosition();
3389
3311
  ctx.advance();
3390
3312
  const nextToken = ctx.peek();
3391
3313
  const tokenAfterNext = ctx.peekAt(1);
3392
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.OF) {
3314
+ if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS.OF) {
3393
3315
  const propertyToken = ctx.advance();
3394
- if (ctx.check(KEYWORDS$1.OF)) {
3316
+ if (ctx.check(KEYWORDS.OF)) {
3395
3317
  ctx.advance();
3396
3318
  const targetToken = ctx.advance();
3397
3319
  const isIdSelector = targetToken.value.startsWith('#');
@@ -3416,7 +3338,7 @@ function parsePropertyOfTarget(ctx, startPosition) {
3416
3338
  ctx.restorePosition(startPosition);
3417
3339
  return null;
3418
3340
  }
3419
- if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS$1.TO) {
3341
+ if (nextToken && tokenAfterNext && tokenAfterNext.value === KEYWORDS.TO) {
3420
3342
  const variableToken = ctx.advance();
3421
3343
  return {
3422
3344
  type: 'identifier',
@@ -3444,11 +3366,11 @@ function parseTargetFallback(ctx) {
3444
3366
  }
3445
3367
  const targetTokens = [];
3446
3368
  while (!ctx.isAtEnd() &&
3447
- !ctx.check(KEYWORDS$1.TO) &&
3448
- !ctx.check(KEYWORDS$1.THEN) &&
3449
- !ctx.check(KEYWORDS$1.AND) &&
3450
- !ctx.check(KEYWORDS$1.ELSE) &&
3451
- !ctx.check(KEYWORDS$1.END)) {
3369
+ !ctx.check(KEYWORDS.TO) &&
3370
+ !ctx.check(KEYWORDS.THEN) &&
3371
+ !ctx.check(KEYWORDS.AND) &&
3372
+ !ctx.check(KEYWORDS.ELSE) &&
3373
+ !ctx.check(KEYWORDS.END)) {
3452
3374
  targetTokens.push(ctx.parsePrimary());
3453
3375
  }
3454
3376
  if (targetTokens.length === 0) {
@@ -3456,8 +3378,8 @@ function parseTargetFallback(ctx) {
3456
3378
  }
3457
3379
  if (targetTokens.length >= 4) {
3458
3380
  const nodeStr = (node, key) => node[key];
3459
- if (nodeStr(targetTokens[0], 'value') === KEYWORDS$1.THE &&
3460
- nodeStr(targetTokens[2], 'value') === KEYWORDS$1.OF) {
3381
+ if (nodeStr(targetTokens[0], 'value') === KEYWORDS.THE &&
3382
+ nodeStr(targetTokens[2], 'value') === KEYWORDS.OF) {
3461
3383
  const propToken = targetTokens[1];
3462
3384
  const targetToken = targetTokens[3];
3463
3385
  return {
@@ -3510,7 +3432,7 @@ function parseSetCommand(ctx, identifierNode) {
3510
3432
  targetExpression = fallback.expression;
3511
3433
  fallbackTokens = fallback.tokens;
3512
3434
  }
3513
- if (!ctx.check(KEYWORDS$1.TO)) {
3435
+ if (!ctx.check(KEYWORDS.TO)) {
3514
3436
  const found = ctx.isAtEnd() ? 'end of input' : ctx.peek().value;
3515
3437
  throw new Error(`Expected 'to' in set command, found: ${found}`);
3516
3438
  }
@@ -3523,7 +3445,7 @@ function parseSetCommand(ctx, identifierNode) {
3523
3445
  else if (fallbackTokens.length > 0) {
3524
3446
  finalArgs.push(...fallbackTokens);
3525
3447
  }
3526
- finalArgs.push(ctx.createIdentifier(KEYWORDS$1.TO));
3448
+ finalArgs.push(ctx.createIdentifier(KEYWORDS.TO));
3527
3449
  if (value) {
3528
3450
  finalArgs.push(value);
3529
3451
  }
@@ -3537,7 +3459,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
3537
3459
  const isIncrement = commandName === 'increment';
3538
3460
  const operator = isIncrement ? '+' : '-';
3539
3461
  let hasGlobal = false;
3540
- if (ctx.check(KEYWORDS$1.GLOBAL)) {
3462
+ if (ctx.check(KEYWORDS.GLOBAL)) {
3541
3463
  hasGlobal = true;
3542
3464
  ctx.advance();
3543
3465
  }
@@ -3546,7 +3468,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
3546
3468
  throw new Error(`Expected variable or expression after ${commandName}`);
3547
3469
  }
3548
3470
  let amount;
3549
- if (ctx.check(KEYWORDS$1.BY)) {
3471
+ if (ctx.check(KEYWORDS.BY)) {
3550
3472
  ctx.advance();
3551
3473
  const parsedAmount = ctx.parseExpression();
3552
3474
  if (!parsedAmount) {
@@ -3577,7 +3499,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
3577
3499
  column: commandToken.column,
3578
3500
  };
3579
3501
  const binaryExpr = createBinaryExpression(operator, target, amount, pos);
3580
- const toIdentifier = createIdentifier(KEYWORDS$1.TO, pos);
3502
+ const toIdentifier = createIdentifier(KEYWORDS.TO, pos);
3581
3503
  const args = [targetWithScope, toIdentifier, binaryExpr];
3582
3504
  return CommandNodeBuilder.from(commandToken)
3583
3505
  .withName('set')
@@ -3794,12 +3716,12 @@ function parseJsCommand(ctx, identifierNode) {
3794
3716
  ctx.consume(')', 'Expected ) after js parameters');
3795
3717
  }
3796
3718
  const jsCodeStart = ctx.peek().start;
3797
- while (!ctx.check(KEYWORDS$1.END) && !ctx.isAtEnd()) {
3719
+ while (!ctx.check(KEYWORDS.END) && !ctx.isAtEnd()) {
3798
3720
  ctx.advance();
3799
3721
  }
3800
3722
  const endToken = ctx.peek();
3801
3723
  const jsCodeEnd = endToken.start;
3802
- ctx.consume(KEYWORDS$1.END, 'Expected end after js code body');
3724
+ ctx.consume(KEYWORDS.END, 'Expected end after js code body');
3803
3725
  const rawSlice = ctx.getInputSlice(jsCodeStart, jsCodeEnd);
3804
3726
  const code = rawSlice.trim();
3805
3727
  const codeNode = {
@@ -3845,10 +3767,10 @@ function parseTellCommand(ctx, identifierNode) {
3845
3767
  catch {
3846
3768
  break;
3847
3769
  }
3848
- if (ctx.match(KEYWORDS$1.AND)) {
3770
+ if (ctx.match(KEYWORDS.AND)) {
3849
3771
  continue;
3850
3772
  }
3851
- if (ctx.check(KEYWORDS$1.THEN) || ctx.check(KEYWORDS$1.ELSE) || ctx.check(KEYWORDS$1.END)) {
3773
+ if (ctx.check(KEYWORDS.THEN) || ctx.check(KEYWORDS.ELSE) || ctx.check(KEYWORDS.END)) {
3852
3774
  break;
3853
3775
  }
3854
3776
  if (ctx.checkIsCommand()) {
@@ -3869,6 +3791,292 @@ function parseTellCommand(ctx, identifierNode) {
3869
3791
  .build();
3870
3792
  }
3871
3793
 
3794
+ const STOP_TOKENS = new Set([
3795
+ 'then',
3796
+ 'end',
3797
+ 'to',
3798
+ 'into',
3799
+ 'on',
3800
+ 'with',
3801
+ 'from',
3802
+ 'in',
3803
+ 'by',
3804
+ 'for',
3805
+ 'while',
3806
+ 'until',
3807
+ 'unless',
3808
+ 'else',
3809
+ 'catch',
3810
+ 'finally',
3811
+ ]);
3812
+ const STOP_DELIMITERS = new Set([')', ']', '}', ',']);
3813
+ function mergeFragments(...fragments) {
3814
+ const merged = new Map();
3815
+ for (const fragment of fragments) {
3816
+ for (const [key, entry] of fragment) {
3817
+ const existing = merged.get(key);
3818
+ if (existing) {
3819
+ merged.set(key, {
3820
+ prefix: entry.prefix ?? existing.prefix,
3821
+ infix: entry.infix ?? existing.infix,
3822
+ });
3823
+ }
3824
+ else {
3825
+ merged.set(key, { ...entry });
3826
+ }
3827
+ }
3828
+ }
3829
+ return merged;
3830
+ }
3831
+ function leftAssoc(bp, handler) {
3832
+ return {
3833
+ infix: {
3834
+ bp: [bp, bp + 1],
3835
+ handler: handler ??
3836
+ ((left, token, ctx) => ({
3837
+ type: 'binaryExpression',
3838
+ operator: token.value,
3839
+ left,
3840
+ right: ctx.parseExpr(bp + 1),
3841
+ start: left.start,
3842
+ })),
3843
+ },
3844
+ };
3845
+ }
3846
+ function rightAssoc(bp, handler) {
3847
+ return {
3848
+ infix: {
3849
+ bp: [bp + 1, bp],
3850
+ handler: ((left, token, ctx) => ({
3851
+ type: 'binaryExpression',
3852
+ operator: token.value,
3853
+ left,
3854
+ right: ctx.parseExpr(bp),
3855
+ start: left.start,
3856
+ })),
3857
+ },
3858
+ };
3859
+ }
3860
+ function prefix(bp, handler) {
3861
+ return {
3862
+ prefix: {
3863
+ bp,
3864
+ handler: handler ??
3865
+ ((token, ctx) => ({
3866
+ type: 'unaryExpression',
3867
+ operator: token.value,
3868
+ operand: ctx.parseExpr(bp),
3869
+ start: token.start,
3870
+ })),
3871
+ },
3872
+ };
3873
+ }
3874
+ const CORE_FRAGMENT = new Map([
3875
+ ['or', leftAssoc(10)],
3876
+ ['||', leftAssoc(10)],
3877
+ ['and', leftAssoc(20)],
3878
+ ['&&', leftAssoc(20)],
3879
+ ['==', leftAssoc(30)],
3880
+ ['!=', leftAssoc(30)],
3881
+ ['<', leftAssoc(30)],
3882
+ ['>', leftAssoc(30)],
3883
+ ['<=', leftAssoc(30)],
3884
+ ['>=', leftAssoc(30)],
3885
+ ['is', leftAssoc(30)],
3886
+ ['matches', leftAssoc(30)],
3887
+ ['contains', leftAssoc(30)],
3888
+ ['+', { ...leftAssoc(40), ...prefix(80) }],
3889
+ ['-', { ...leftAssoc(40), ...prefix(80) }],
3890
+ ['*', leftAssoc(50)],
3891
+ ['/', leftAssoc(50)],
3892
+ ['%', leftAssoc(50)],
3893
+ ['mod', leftAssoc(50)],
3894
+ ['^', rightAssoc(60)],
3895
+ ['**', rightAssoc(60)],
3896
+ [
3897
+ 'as',
3898
+ leftAssoc(70, (left, _token, ctx) => ({
3899
+ type: 'asExpression',
3900
+ expression: left,
3901
+ targetType: ctx.parseExpr(71),
3902
+ start: left.start,
3903
+ })),
3904
+ ],
3905
+ ['not', prefix(80)],
3906
+ ['!', prefix(80)],
3907
+ ['no', prefix(80)],
3908
+ ]);
3909
+ const POSITIONAL_FRAGMENT = new Map([
3910
+ [
3911
+ 'first',
3912
+ prefix(85, (token, ctx) => ({
3913
+ type: 'positionalExpression',
3914
+ position: 'first',
3915
+ operand: ctx.parseExpr(85),
3916
+ start: token.start,
3917
+ })),
3918
+ ],
3919
+ [
3920
+ 'last',
3921
+ prefix(85, (token, ctx) => ({
3922
+ type: 'positionalExpression',
3923
+ position: 'last',
3924
+ operand: ctx.parseExpr(85),
3925
+ start: token.start,
3926
+ })),
3927
+ ],
3928
+ ]);
3929
+ const PROPERTY_FRAGMENT = new Map([
3930
+ [
3931
+ '.',
3932
+ {
3933
+ infix: {
3934
+ bp: [90, 91],
3935
+ handler: (left, _token, ctx) => {
3936
+ const propToken = ctx.advance();
3937
+ return {
3938
+ type: 'propertyAccess',
3939
+ object: left,
3940
+ property: propToken.value,
3941
+ start: left.start,
3942
+ };
3943
+ },
3944
+ },
3945
+ },
3946
+ ],
3947
+ [
3948
+ '?.',
3949
+ {
3950
+ infix: {
3951
+ bp: [90, 91],
3952
+ handler: (left, _token, ctx) => {
3953
+ const propToken = ctx.advance();
3954
+ return {
3955
+ type: 'optionalChain',
3956
+ object: left,
3957
+ property: propToken.value,
3958
+ start: left.start,
3959
+ };
3960
+ },
3961
+ },
3962
+ },
3963
+ ],
3964
+ [
3965
+ "'s",
3966
+ {
3967
+ infix: {
3968
+ bp: [95, 96],
3969
+ handler: (left, _token, ctx) => {
3970
+ const propToken = ctx.advance();
3971
+ return {
3972
+ type: 'possessiveExpression',
3973
+ object: left,
3974
+ property: propToken.value,
3975
+ start: left.start,
3976
+ };
3977
+ },
3978
+ },
3979
+ },
3980
+ ],
3981
+ ]);
3982
+ const PARSER_COMPARISON_FRAGMENT = new Map([
3983
+ ['===', leftAssoc(30)],
3984
+ ['!==', leftAssoc(30)],
3985
+ ['is not', leftAssoc(30)],
3986
+ ['is a', leftAssoc(30)],
3987
+ ['is an', leftAssoc(30)],
3988
+ ['is not a', leftAssoc(30)],
3989
+ ['is not an', leftAssoc(30)],
3990
+ ['is in', leftAssoc(30)],
3991
+ ['is not in', leftAssoc(30)],
3992
+ ['has', leftAssoc(30)],
3993
+ ['have', leftAssoc(30)],
3994
+ ['match', leftAssoc(30)],
3995
+ ['include', leftAssoc(30)],
3996
+ ['includes', leftAssoc(30)],
3997
+ ['equals', leftAssoc(30)],
3998
+ ['does not contain', leftAssoc(30)],
3999
+ ['does not include', leftAssoc(30)],
4000
+ ['in', leftAssoc(30)],
4001
+ ['of', leftAssoc(30)],
4002
+ ['really', leftAssoc(30)],
4003
+ [
4004
+ 'exists',
4005
+ {
4006
+ prefix: {
4007
+ bp: 80,
4008
+ handler: (token, ctx) => ({
4009
+ type: 'unaryExpression',
4010
+ operator: token.value,
4011
+ operand: ctx.parseExpr(80),
4012
+ start: token.start,
4013
+ }),
4014
+ },
4015
+ infix: {
4016
+ bp: [30, 31],
4017
+ handler: (left, token) => ({
4018
+ type: 'unaryExpression',
4019
+ operator: token.value,
4020
+ operand: left,
4021
+ prefix: false,
4022
+ start: left.start,
4023
+ }),
4024
+ },
4025
+ },
4026
+ ],
4027
+ [
4028
+ 'does not exist',
4029
+ {
4030
+ infix: {
4031
+ bp: [30, 31],
4032
+ handler: (left, token) => ({
4033
+ type: 'unaryExpression',
4034
+ operator: token.value,
4035
+ operand: left,
4036
+ prefix: false,
4037
+ start: left.start,
4038
+ }),
4039
+ },
4040
+ },
4041
+ ],
4042
+ [
4043
+ 'is empty',
4044
+ {
4045
+ infix: {
4046
+ bp: [30, 31],
4047
+ handler: (left, token) => ({
4048
+ type: 'unaryExpression',
4049
+ operator: token.value,
4050
+ operand: left,
4051
+ prefix: false,
4052
+ start: left.start,
4053
+ }),
4054
+ },
4055
+ },
4056
+ ],
4057
+ [
4058
+ 'is not empty',
4059
+ {
4060
+ infix: {
4061
+ bp: [30, 31],
4062
+ handler: (left, token) => ({
4063
+ type: 'unaryExpression',
4064
+ operator: token.value,
4065
+ operand: left,
4066
+ prefix: false,
4067
+ start: left.start,
4068
+ }),
4069
+ },
4070
+ },
4071
+ ],
4072
+ ['some', prefix(80)],
4073
+ ]);
4074
+ const ASSIGNMENT_FRAGMENT = new Map([
4075
+ ['=', rightAssoc(5)],
4076
+ ]);
4077
+ mergeFragments(CORE_FRAGMENT, POSITIONAL_FRAGMENT, PROPERTY_FRAGMENT);
4078
+ const PARSER_TABLE = mergeFragments(CORE_FRAGMENT, PARSER_COMPARISON_FRAGMENT, ASSIGNMENT_FRAGMENT);
4079
+
3872
4080
  function parseTimeToMs(timeStr) {
3873
4081
  if (timeStr.endsWith('ms'))
3874
4082
  return parseInt(timeStr, 10);
@@ -3887,7 +4095,9 @@ function parseTimeToMs(timeStr) {
3887
4095
  class Parser {
3888
4096
  constructor(tokens, options, originalInput) {
3889
4097
  this.current = 0;
4098
+ this.errors = [];
3890
4099
  this.warnings = [];
4100
+ this.prattCache = new Map();
3891
4101
  this.tokens = tokens;
3892
4102
  this.keywordResolver = options?.keywords;
3893
4103
  this.registryIntegration = options?.registryIntegration;
@@ -3910,6 +4120,14 @@ class Parser {
3910
4120
  this.warnings.push(warning);
3911
4121
  }
3912
4122
  parse() {
4123
+ this.prattCache.clear();
4124
+ const result = this.parseInternal();
4125
+ if (this.errors.length > 0) {
4126
+ result.errors = [...this.errors];
4127
+ }
4128
+ return result;
4129
+ }
4130
+ parseInternal() {
3913
4131
  try {
3914
4132
  if (this.tokens.length === 0) {
3915
4133
  this.addError('Cannot parse empty input');
@@ -4125,7 +4343,114 @@ class Parser {
4125
4343
  }
4126
4344
  }
4127
4345
  parseExpression() {
4128
- return this.parseAssignment();
4346
+ return this.parseExpressionPratt(0);
4347
+ }
4348
+ parseExpressionPratt(minBp) {
4349
+ const cacheKey = `${this.current}:${minBp}`;
4350
+ const cached = this.prattCache.get(cacheKey);
4351
+ if (cached) {
4352
+ this.current = cached.endPos;
4353
+ return cached.node;
4354
+ }
4355
+ this.current;
4356
+ if (this.isAtEnd()) {
4357
+ this.addError('Unexpected end of expression');
4358
+ return this.createErrorNode();
4359
+ }
4360
+ const firstToken = this.peek();
4361
+ const prefixEntry = Parser.PRATT_TABLE.get(firstToken.value);
4362
+ let left;
4363
+ if (prefixEntry?.prefix) {
4364
+ const token = this.advance();
4365
+ if (this.isAtEnd()) {
4366
+ this.addError(`Expected expression after '${token.value}' operator`);
4367
+ return this.createErrorNode();
4368
+ }
4369
+ left = prefixEntry.prefix.handler(token, this.makePrattContext());
4370
+ }
4371
+ else {
4372
+ left = this.parseCall();
4373
+ }
4374
+ while (!this.isAtEnd()) {
4375
+ const nextToken = this.peek();
4376
+ const infixEntry = Parser.PRATT_TABLE.get(nextToken.value);
4377
+ if (!infixEntry?.infix) {
4378
+ if (STOP_TOKENS.has(nextToken.value) || STOP_DELIMITERS.has(nextToken.value)) {
4379
+ break;
4380
+ }
4381
+ break;
4382
+ }
4383
+ const [leftBp] = infixEntry.infix.bp;
4384
+ if (leftBp < minBp)
4385
+ break;
4386
+ if (nextToken.value === '=') {
4387
+ if (this.current + 1 < this.tokens.length && this.tokens[this.current + 1].value === '>') {
4388
+ this.advance();
4389
+ this.advance();
4390
+ this.addError('Arrow functions (=>) are not supported in hyperscript. ' +
4391
+ 'Use "js ... end" blocks for JavaScript callbacks.');
4392
+ if (!this.isAtEnd()) {
4393
+ try {
4394
+ this.parseExpressionPratt(0);
4395
+ }
4396
+ catch {
4397
+ }
4398
+ }
4399
+ return this.createErrorNode();
4400
+ }
4401
+ }
4402
+ if (nextToken.value === '+' || nextToken.value === '-') {
4403
+ const afterOp = this.current + 1 < this.tokens.length ? this.tokens[this.current + 1] : null;
4404
+ if (afterOp && (afterOp.value === '+' || afterOp.value === '-')) {
4405
+ this.addError(`Invalid operator combination: ${nextToken.value}${afterOp.value}`);
4406
+ return left;
4407
+ }
4408
+ }
4409
+ if (nextToken.value === '*' || nextToken.value === '/' || nextToken.value === '%') {
4410
+ const afterOp = this.current + 1 < this.tokens.length ? this.tokens[this.current + 1] : null;
4411
+ if (afterOp &&
4412
+ (afterOp.value === '*' ||
4413
+ afterOp.value === '/' ||
4414
+ afterOp.value === '%' ||
4415
+ afterOp.value === '+' ||
4416
+ afterOp.value === '-')) {
4417
+ if (nextToken.value === '*' && afterOp.value === '*') {
4418
+ this.addError(`Unexpected token: ${afterOp.value}`);
4419
+ }
4420
+ else {
4421
+ this.addError(`Invalid operator combination: ${nextToken.value}${afterOp.value}`);
4422
+ }
4423
+ return left;
4424
+ }
4425
+ }
4426
+ const opToken = this.advance();
4427
+ if (this.isAtEnd() && !Parser.POSTFIX_UNARY_OPERATORS.has(opToken.value)) {
4428
+ this.addError(`Expected expression after '${opToken.value}' operator`);
4429
+ return left;
4430
+ }
4431
+ left = infixEntry.infix.handler(left, opToken, this.makePrattContext());
4432
+ }
4433
+ this.prattCache.set(cacheKey, { node: left, endPos: this.current });
4434
+ return left;
4435
+ }
4436
+ makePrattContext() {
4437
+ const self = this;
4438
+ return {
4439
+ peek: () => (self.current < self.tokens.length ? self.tokens[self.current] : undefined),
4440
+ advance: () => {
4441
+ const token = self.tokens[self.current];
4442
+ self.current++;
4443
+ return token;
4444
+ },
4445
+ parseExpr: (bp) => self.parseExpressionPratt(bp),
4446
+ isStopToken: () => {
4447
+ const t = self.tokens[self.current];
4448
+ if (!t)
4449
+ return true;
4450
+ return STOP_TOKENS.has(t.value) || STOP_DELIMITERS.has(t.value);
4451
+ },
4452
+ atEnd: () => self.current >= self.tokens.length,
4453
+ };
4129
4454
  }
4130
4455
  parseAssignment() {
4131
4456
  let expr = this.parseLogicalOr();
@@ -5644,7 +5969,23 @@ class Parser {
5644
5969
  break;
5645
5970
  }
5646
5971
  else {
5647
- this.addError(`Expected command, got: ${this.peek().value}`);
5972
+ const errorToken = this.peek();
5973
+ const errorPos = this.getPosition();
5974
+ const errorMessage = `Expected command, got: ${errorToken.value}`;
5975
+ this.addError(errorMessage);
5976
+ const errorNode = createErrorCommandNode(errorPos, errorMessage, errorToken.value);
5977
+ commands.push(errorNode);
5978
+ this.synchronizeToCommandBoundary();
5979
+ if (this.isAtEnd())
5980
+ break;
5981
+ if (this.match('then'))
5982
+ continue;
5983
+ if (this.check('end') || this.check('on'))
5984
+ break;
5985
+ if (this.checkIsCommand() ||
5986
+ (this.isCommand(this.peek().value) && !this.isKeyword(this.peek().value))) {
5987
+ continue;
5988
+ }
5648
5989
  break;
5649
5990
  }
5650
5991
  }
@@ -6275,6 +6616,20 @@ class Parser {
6275
6616
  column: Math.max(1, column),
6276
6617
  position: Math.max(0, position),
6277
6618
  };
6619
+ this.errors.push(this.error);
6620
+ }
6621
+ synchronizeToCommandBoundary() {
6622
+ while (!this.isAtEnd()) {
6623
+ const token = this.peek();
6624
+ if (token.value === 'then' || token.value === 'end' || token.value === 'on') {
6625
+ return;
6626
+ }
6627
+ if (this.checkIsCommand() || (this.isCommand(token.value) && !this.isKeyword(token.value))) {
6628
+ return;
6629
+ }
6630
+ debug.parse('⚠️ synchronize: Skipping token:', token.value);
6631
+ this.advance();
6632
+ }
6278
6633
  }
6279
6634
  parseAttributeOrArrayLiteral() {
6280
6635
  const startPos = this.previous().start;
@@ -6425,6 +6780,7 @@ Parser.POSTFIX_UNARY_OPERATORS = new Set([
6425
6780
  'is empty',
6426
6781
  'is not empty',
6427
6782
  ]);
6783
+ Parser.PRATT_TABLE = PARSER_TABLE;
6428
6784
  Parser.PSEUDO_COMMAND_PREPOSITIONS = ['from', 'on', 'with', 'into', 'at', 'to'];
6429
6785
 
6430
6786
  class FullParserImpl {