@hyperfixi/core 2.8.0 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/dist/ast-utils/index.js +1201 -891
- package/dist/ast-utils/index.mjs +1201 -891
- package/dist/chunks/{bridge-DHj-SYm2.js → bridge-BYhqTOnL.js} +2 -2
- package/dist/chunks/browser-modular-D2BHzZFB.js +2 -0
- package/dist/chunks/feature-eventsource-Bxg_UNZo.js +2 -0
- package/dist/chunks/feature-sockets-CcTxD5sT.js +2 -0
- package/dist/chunks/feature-webworker-DoqZ0Grg.js +2 -0
- package/dist/chunks/{index-CuPeasRm.js → index-DXgJaDj-.js} +2 -2
- package/dist/commands/index.js +168 -112
- package/dist/commands/index.mjs +168 -112
- package/dist/hyperfixi-browser-classic-i18n.js +1 -1
- package/dist/hyperfixi-browser-minimal.js +1 -1
- package/dist/hyperfixi-browser-standard.js +1 -1
- package/dist/hyperfixi-browser.js +1 -1
- package/dist/hyperfixi-classic-i18n.js +1 -1
- package/dist/hyperfixi-hx-v4.js +1 -1
- package/dist/hyperfixi-minimal.js +1 -1
- package/dist/hyperfixi-multilingual.js +1 -1
- package/dist/hyperfixi-standard.js +1 -1
- package/dist/hyperfixi.js +1 -1
- package/dist/hyperfixi.mjs +1 -1
- package/dist/index.js +2119 -1538
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +2119 -1538
- package/dist/lokascript-browser-classic-i18n.js +1 -1
- package/dist/lokascript-browser-minimal.js +1 -1
- package/dist/lokascript-browser-standard.js +1 -1
- package/dist/lokascript-browser.js +1 -1
- package/dist/lokascript-multilingual.js +1 -1
- package/dist/lsp-metadata.js +5 -5
- package/dist/lsp-metadata.mjs +5 -5
- package/dist/metadata.js +25 -25
- package/dist/metadata.mjs +25 -25
- package/dist/multilingual/index.js +17 -17
- package/dist/multilingual/index.mjs +17 -17
- package/dist/parser/command-parsers/utility-commands.d.ts +1 -0
- package/dist/parser/full-parser.js +155 -106
- package/dist/parser/full-parser.mjs +155 -106
- package/dist/parser/parser.d.ts +1 -0
- package/dist/reference/index.js +1 -0
- package/dist/reference/index.mjs +1 -0
- package/dist/registry/index.js +155 -106
- package/dist/registry/index.mjs +155 -106
- package/dist/types/base-types.d.ts +3 -0
- package/package.json +7 -6
- package/dist/chunks/browser-modular-D1m0Eikh.js +0 -2
- package/dist/chunks/feature-eventsource-BpZvPy_K.js +0 -2
- package/dist/chunks/feature-sockets-CrYvjZ4j.js +0 -2
- package/dist/chunks/feature-webworker-BSYguEIW.js +0 -2
package/dist/registry/index.js
CHANGED
|
@@ -33,39 +33,39 @@ const DEBUG = {
|
|
|
33
33
|
const debug = {
|
|
34
34
|
command: (...args) => {
|
|
35
35
|
if (DEBUG.commands)
|
|
36
|
-
console.log('
|
|
36
|
+
console.log('\ud83d\udd27', ...args);
|
|
37
37
|
},
|
|
38
38
|
event: (...args) => {
|
|
39
39
|
if (DEBUG.events)
|
|
40
|
-
console.log('
|
|
40
|
+
console.log('\ud83c\udfaf', ...args);
|
|
41
41
|
},
|
|
42
42
|
parse: (...args) => {
|
|
43
43
|
if (DEBUG.parsing)
|
|
44
|
-
console.log('
|
|
44
|
+
console.log('\ud83d\udcdd', ...args);
|
|
45
45
|
},
|
|
46
46
|
expr: (...args) => {
|
|
47
47
|
if (DEBUG.expressions)
|
|
48
|
-
console.log('
|
|
48
|
+
console.log('\ud83d\udd0d', ...args);
|
|
49
49
|
},
|
|
50
50
|
expressions: (...args) => {
|
|
51
51
|
if (DEBUG.expressions)
|
|
52
|
-
console.log('
|
|
52
|
+
console.log('\ud83d\udd0d', ...args);
|
|
53
53
|
},
|
|
54
54
|
style: (...args) => {
|
|
55
55
|
if (DEBUG.styles)
|
|
56
|
-
console.log('
|
|
56
|
+
console.log('\ud83c\udfa8', ...args);
|
|
57
57
|
},
|
|
58
58
|
runtime: (...args) => {
|
|
59
59
|
if (DEBUG.runtime)
|
|
60
|
-
console.log('
|
|
60
|
+
console.log('\ud83d\ude80', ...args);
|
|
61
61
|
},
|
|
62
62
|
loop: (...args) => {
|
|
63
63
|
if (DEBUG.loops)
|
|
64
|
-
console.log('
|
|
64
|
+
console.log('\ud83d\udd01', ...args);
|
|
65
65
|
},
|
|
66
66
|
async: (...args) => {
|
|
67
67
|
if (DEBUG.async)
|
|
68
|
-
console.log('
|
|
68
|
+
console.log('\u23f3', ...args);
|
|
69
69
|
},
|
|
70
70
|
};
|
|
71
71
|
|
|
@@ -4048,6 +4048,7 @@ function tokenize(input) {
|
|
|
4048
4048
|
const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
|
|
4049
4049
|
const isPossessive = nextChar === 's' &&
|
|
4050
4050
|
prevToken &&
|
|
4051
|
+
!/\s/.test(tokenizer.input[tokenizer.position - 1] ?? ' ') &&
|
|
4051
4052
|
(prevToken.kind === TokenKind.IDENTIFIER ||
|
|
4052
4053
|
prevToken.kind === TokenKind.SELECTOR ||
|
|
4053
4054
|
prevToken.value === ']' ||
|
|
@@ -5772,9 +5773,9 @@ function createPartialCommandNode(name, pos) {
|
|
|
5772
5773
|
};
|
|
5773
5774
|
}
|
|
5774
5775
|
function createProgramNode(statements) {
|
|
5775
|
-
debug.parse(
|
|
5776
|
+
debug.parse(`\u2705 createProgramNode: Called with ${statements.length} statements`);
|
|
5776
5777
|
if (statements.length === 0) {
|
|
5777
|
-
debug.parse(
|
|
5778
|
+
debug.parse(`\u2705 createProgramNode: Returning error node (0 statements)`);
|
|
5778
5779
|
return {
|
|
5779
5780
|
type: 'identifier',
|
|
5780
5781
|
name: '__ERROR__',
|
|
@@ -5785,7 +5786,7 @@ function createProgramNode(statements) {
|
|
|
5785
5786
|
};
|
|
5786
5787
|
}
|
|
5787
5788
|
if (statements.length === 1) {
|
|
5788
|
-
debug.parse(
|
|
5789
|
+
debug.parse(`\u2705 createProgramNode: Returning single statement (type=${statements[0].type})`);
|
|
5789
5790
|
return statements[0];
|
|
5790
5791
|
}
|
|
5791
5792
|
const programNode = {
|
|
@@ -5796,7 +5797,7 @@ function createProgramNode(statements) {
|
|
|
5796
5797
|
line: statements[0]?.line || 1,
|
|
5797
5798
|
column: statements[0]?.column || 1,
|
|
5798
5799
|
};
|
|
5799
|
-
debug.parse(
|
|
5800
|
+
debug.parse(`\u2705 createProgramNode: Returning Program node with ${statements.length} statements, type=${programNode.type}`);
|
|
5800
5801
|
return programNode;
|
|
5801
5802
|
}
|
|
5802
5803
|
|
|
@@ -6185,37 +6186,37 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
6185
6186
|
ctx.advance();
|
|
6186
6187
|
loopType = 'until-event';
|
|
6187
6188
|
const eventToken = ctx.peek();
|
|
6188
|
-
debug.parse('
|
|
6189
|
+
debug.parse('\ud83d\udccd Parsing event name, current token:', {
|
|
6189
6190
|
value: eventToken.value,
|
|
6190
6191
|
kind: eventToken.kind,
|
|
6191
6192
|
});
|
|
6192
6193
|
if (isIdentifierLike(eventToken) || isEvent(eventToken)) {
|
|
6193
6194
|
eventName = eventToken.value;
|
|
6194
6195
|
ctx.advance();
|
|
6195
|
-
debug.parse('
|
|
6196
|
+
debug.parse('\u2705 Got event name:', eventName, 'Next token:', ctx.peek().value);
|
|
6196
6197
|
}
|
|
6197
6198
|
else {
|
|
6198
6199
|
throw new Error('Expected event name after "event"');
|
|
6199
6200
|
}
|
|
6200
|
-
debug.parse('
|
|
6201
|
+
debug.parse('\ud83d\udd0d Checking for "from", current token:', ctx.peek().value);
|
|
6201
6202
|
if (ctx.check(KEYWORDS.FROM)) {
|
|
6202
|
-
debug.parse('
|
|
6203
|
+
debug.parse('\u2705 Found "from", advancing...');
|
|
6203
6204
|
ctx.advance();
|
|
6204
|
-
debug.parse('
|
|
6205
|
+
debug.parse('\ud83d\udccd After consuming "from", current token:', ctx.peek().value);
|
|
6205
6206
|
if (consumeOptionalKeyword(ctx, KEYWORDS.THE)) {
|
|
6206
|
-
debug.parse('
|
|
6207
|
+
debug.parse('\u2705 Found "the", advancing...');
|
|
6207
6208
|
}
|
|
6208
6209
|
const beforePrimary = ctx.peek();
|
|
6209
|
-
debug.parse('
|
|
6210
|
+
debug.parse('\ud83d\udd0d Before parsePrimary for event target:', {
|
|
6210
6211
|
value: beforePrimary.value,
|
|
6211
6212
|
kind: beforePrimary.kind,
|
|
6212
6213
|
position: beforePrimary.start,
|
|
6213
6214
|
});
|
|
6214
6215
|
eventTarget = ctx.parsePrimary();
|
|
6215
|
-
debug.parse('
|
|
6216
|
+
debug.parse('\u2705 After parsePrimary, eventTarget:', eventTarget);
|
|
6216
6217
|
}
|
|
6217
6218
|
else {
|
|
6218
|
-
debug.parse('
|
|
6219
|
+
debug.parse('\u274c No "from" found, skipping target parsing');
|
|
6219
6220
|
}
|
|
6220
6221
|
}
|
|
6221
6222
|
else {
|
|
@@ -7316,16 +7317,6 @@ function stringNode(value, tok) {
|
|
|
7316
7317
|
column: tok.column,
|
|
7317
7318
|
};
|
|
7318
7319
|
}
|
|
7319
|
-
function isNakedURLStart(ctx) {
|
|
7320
|
-
const tok = ctx.peek();
|
|
7321
|
-
if (tok.value === '/')
|
|
7322
|
-
return true;
|
|
7323
|
-
if (ctx.checkIdentifierLike()) {
|
|
7324
|
-
const next = ctx.peekAt(1);
|
|
7325
|
-
return !!next && next.value === ':' && next.start === tok.end;
|
|
7326
|
-
}
|
|
7327
|
-
return false;
|
|
7328
|
-
}
|
|
7329
7320
|
function parseGoCommand(ctx, identifierNode) {
|
|
7330
7321
|
const args = [];
|
|
7331
7322
|
while (!isCommandBoundary(ctx, ['when', 'where', 'catch', 'finally'])) {
|
|
@@ -7484,6 +7475,16 @@ function isFetchURLTerminator(ctx) {
|
|
|
7484
7475
|
return (['as', 'with', '{', 'then', 'end', 'else', 'otherwise', ')'].includes(val) ||
|
|
7485
7476
|
isCommandBoundary(ctx));
|
|
7486
7477
|
}
|
|
7478
|
+
function isNakedURLStart(ctx) {
|
|
7479
|
+
const tok = ctx.peek();
|
|
7480
|
+
if (tok.value === '/')
|
|
7481
|
+
return true;
|
|
7482
|
+
if (ctx.checkIdentifierLike()) {
|
|
7483
|
+
const next = ctx.peekAt(1);
|
|
7484
|
+
return !!next && next.value === ':' && next.start === tok.end;
|
|
7485
|
+
}
|
|
7486
|
+
return false;
|
|
7487
|
+
}
|
|
7487
7488
|
function parseBareURLPath(ctx, isTerminator = isFetchURLTerminator) {
|
|
7488
7489
|
const startPos = ctx.savePosition();
|
|
7489
7490
|
let path = '';
|
|
@@ -7505,7 +7506,7 @@ function parseBareURLPath(ctx, isTerminator = isFetchURLTerminator) {
|
|
|
7505
7506
|
function parseFetchCommand(ctx, commandToken) {
|
|
7506
7507
|
const modifiers = {};
|
|
7507
7508
|
let url = null;
|
|
7508
|
-
if (!ctx.isAtEnd() && ctx
|
|
7509
|
+
if (!ctx.isAtEnd() && isNakedURLStart(ctx)) {
|
|
7509
7510
|
url = parseBareURLPath(ctx);
|
|
7510
7511
|
}
|
|
7511
7512
|
if (!url) {
|
|
@@ -8071,26 +8072,26 @@ class Parser {
|
|
|
8071
8072
|
const commandSequence = this.parseCommandSequence();
|
|
8072
8073
|
if (commandSequence) {
|
|
8073
8074
|
if (!this.isAtEnd() && this.check('on')) {
|
|
8074
|
-
debug.parse('
|
|
8075
|
+
debug.parse('\u2705 PARSER: Found event handlers after command sequence, parsing as program');
|
|
8075
8076
|
const statements = [commandSequence];
|
|
8076
|
-
debug.parse(
|
|
8077
|
+
debug.parse(`\u2705 PARSER: Starting with ${statements.length} statement(s) from command sequence`);
|
|
8077
8078
|
let eventHandlerCount = 0;
|
|
8078
8079
|
while (!this.isAtEnd() && this.check('on')) {
|
|
8079
|
-
debug.parse(
|
|
8080
|
+
debug.parse(`\u2705 PARSER: Parsing event handler #${eventHandlerCount + 1}, current token: ${this.peek().value}`);
|
|
8080
8081
|
this.advance();
|
|
8081
8082
|
const eventHandler = this.parseEventHandler();
|
|
8082
|
-
debug.parse(
|
|
8083
|
+
debug.parse(`\u2705 PARSER: parseEventHandler returned:`, eventHandler
|
|
8083
8084
|
? `type=${eventHandler.type}, event=${eventHandler.event}`
|
|
8084
8085
|
: 'null');
|
|
8085
8086
|
if (eventHandler) {
|
|
8086
8087
|
statements.push(eventHandler);
|
|
8087
8088
|
eventHandlerCount++;
|
|
8088
|
-
debug.parse(
|
|
8089
|
+
debug.parse(`\u2705 PARSER: Added event handler, now have ${statements.length} statements total`);
|
|
8089
8090
|
}
|
|
8090
|
-
debug.parse(
|
|
8091
|
+
debug.parse(`\u2705 PARSER: After parsing event handler, current token: ${this.isAtEnd() ? 'END' : this.peek().value}, isAtEnd=${this.isAtEnd()}, check('on')=${this.check('on')}`);
|
|
8091
8092
|
if (!this.isAtEnd() && !this.check('on')) {
|
|
8092
8093
|
if (!this.isAtEnd()) {
|
|
8093
|
-
debug.parse(
|
|
8094
|
+
debug.parse(`\u26a0\ufe0f PARSER: Unexpected token after event handlers: ${this.peek().value}`);
|
|
8094
8095
|
this.addError(`Unexpected token after event handlers: ${this.peek().value}`);
|
|
8095
8096
|
return {
|
|
8096
8097
|
success: false,
|
|
@@ -8099,11 +8100,11 @@ class Parser {
|
|
|
8099
8100
|
error: this.error,
|
|
8100
8101
|
};
|
|
8101
8102
|
}
|
|
8102
|
-
debug.parse(
|
|
8103
|
+
debug.parse(`\u2705 PARSER: No more event handlers, at end of input`);
|
|
8103
8104
|
break;
|
|
8104
8105
|
}
|
|
8105
8106
|
}
|
|
8106
|
-
debug.parse(
|
|
8107
|
+
debug.parse(`\u2705 PARSER: Finished parsing, creating Program node with ${statements.length} statements`);
|
|
8107
8108
|
if (this.error) {
|
|
8108
8109
|
return {
|
|
8109
8110
|
success: false,
|
|
@@ -8498,41 +8499,41 @@ class Parser {
|
|
|
8498
8499
|
parseCommandListUntilTerminator(extraStops) {
|
|
8499
8500
|
const commands = [];
|
|
8500
8501
|
const isStop = () => this.check('end') || extraStops.some(s => this.check(s));
|
|
8501
|
-
debug.parse('
|
|
8502
|
+
debug.parse('\ud83d\udd04 parseCommandListUntilTerminator: Starting (extraStops:', extraStops.join(','), ')');
|
|
8502
8503
|
while (!this.isAtEnd() && !isStop()) {
|
|
8503
|
-
debug.parse('
|
|
8504
|
+
debug.parse('\ud83d\udccd Loop iteration, current token:', this.peek().value, 'kind:', this.peek().kind);
|
|
8504
8505
|
let parsedCommand = false;
|
|
8505
8506
|
const isCommandToken = this.checkIsCommand();
|
|
8506
8507
|
const isCommandIdentifier = !isCommandToken && this.checkIdentifier() && this.isCommand(this.peek().value);
|
|
8507
8508
|
if (isCommandToken || isCommandIdentifier) {
|
|
8508
|
-
debug.parse(isCommandToken ? '
|
|
8509
|
+
debug.parse(isCommandToken ? '\u2705 Found COMMAND token:' : '\u2705 Found IDENTIFIER that is a command:', this.peek().value);
|
|
8509
8510
|
this.advance();
|
|
8510
8511
|
const savedError = this.error;
|
|
8511
8512
|
try {
|
|
8512
8513
|
const cmd = this.parseCommand();
|
|
8513
8514
|
if (this.error && this.error !== savedError) {
|
|
8514
|
-
debug.parse('
|
|
8515
|
+
debug.parse('\u26a0\ufe0f parseCommandListUntilTerminator: Command parsing added error, restoring. Error was:', this.error.message);
|
|
8515
8516
|
this.error = savedError;
|
|
8516
8517
|
}
|
|
8517
8518
|
if (cmd) {
|
|
8518
|
-
debug.parse('
|
|
8519
|
+
debug.parse('\u2705 Parsed command:', cmd.name);
|
|
8519
8520
|
commands.push(cmd);
|
|
8520
8521
|
parsedCommand = true;
|
|
8521
8522
|
}
|
|
8522
8523
|
}
|
|
8523
8524
|
catch (error) {
|
|
8524
|
-
debug.parse('
|
|
8525
|
+
debug.parse('\u26a0\ufe0f parseCommandListUntilTerminator: Command parsing threw, restoring:', error instanceof Error ? error.message : String(error));
|
|
8525
8526
|
this.error = savedError;
|
|
8526
8527
|
}
|
|
8527
8528
|
}
|
|
8528
8529
|
else if (this.checkIdentifier()) {
|
|
8529
|
-
debug.parse('
|
|
8530
|
+
debug.parse('\u274c IDENTIFIER is not a command:', this.peek().value);
|
|
8530
8531
|
}
|
|
8531
8532
|
if (!parsedCommand) {
|
|
8532
|
-
debug.parse('
|
|
8533
|
+
debug.parse('\u274c No command parsed, breaking. Current token:', this.peek().value);
|
|
8533
8534
|
break;
|
|
8534
8535
|
}
|
|
8535
|
-
debug.parse('
|
|
8536
|
+
debug.parse('\ud83d\udccd After parsing command, current token:', this.peek().value);
|
|
8536
8537
|
while (!this.isAtEnd() &&
|
|
8537
8538
|
!isStop() &&
|
|
8538
8539
|
!this.checkIsCommand() &&
|
|
@@ -8540,19 +8541,19 @@ class Parser {
|
|
|
8540
8541
|
!this.check('then') &&
|
|
8541
8542
|
!this.check('and') &&
|
|
8542
8543
|
!this.check(',')) {
|
|
8543
|
-
debug.parse('
|
|
8544
|
+
debug.parse('\u26a0\ufe0f Skipping unexpected token:', this.peek().value);
|
|
8544
8545
|
this.advance();
|
|
8545
8546
|
}
|
|
8546
8547
|
if (this.match('then', 'and', ',')) {
|
|
8547
|
-
debug.parse('
|
|
8548
|
+
debug.parse('\u2705 Found separator, continuing');
|
|
8548
8549
|
continue;
|
|
8549
8550
|
}
|
|
8550
8551
|
else if (this.checkIsCommand() || this.isCommand(this.peek().value)) {
|
|
8551
|
-
debug.parse('
|
|
8552
|
+
debug.parse('\u2705 Next token is a command, continuing without separator');
|
|
8552
8553
|
continue;
|
|
8553
8554
|
}
|
|
8554
8555
|
else {
|
|
8555
|
-
debug.parse('
|
|
8556
|
+
debug.parse('\ud83d\udccd No separator and no command, breaking. Current token:', this.peek().value);
|
|
8556
8557
|
break;
|
|
8557
8558
|
}
|
|
8558
8559
|
}
|
|
@@ -8566,18 +8567,18 @@ class Parser {
|
|
|
8566
8567
|
if (!this.check('end') && !extraStops.some(s => this.check(s))) {
|
|
8567
8568
|
terminator = '';
|
|
8568
8569
|
}
|
|
8569
|
-
debug.parse('
|
|
8570
|
+
debug.parse('\u2705 parseCommandListUntilTerminator: parsed', commands.length, 'commands (terminator:', terminator, ')');
|
|
8570
8571
|
return { commands, terminator };
|
|
8571
8572
|
}
|
|
8572
8573
|
parseCommandListUntilEnd() {
|
|
8573
8574
|
const { commands } = this.parseCommandListUntilTerminator([]);
|
|
8574
|
-
debug.parse('
|
|
8575
|
+
debug.parse('\ud83d\udd0d After loop, checking for "end". Current token:', this.peek().value);
|
|
8575
8576
|
if (this.check('end')) {
|
|
8576
|
-
debug.parse('
|
|
8577
|
+
debug.parse('\u2705 Found "end", consuming it');
|
|
8577
8578
|
this.advance();
|
|
8578
8579
|
}
|
|
8579
8580
|
else {
|
|
8580
|
-
debug.parse('
|
|
8581
|
+
debug.parse('\u274c ERROR: Expected "end" but got:', this.peek().value, 'at position:', this.peek().start);
|
|
8581
8582
|
throw new Error('Expected "end" to close repeat block');
|
|
8582
8583
|
}
|
|
8583
8584
|
return commands;
|
|
@@ -9250,6 +9251,23 @@ class Parser {
|
|
|
9250
9251
|
this.consume(')', "Expected ')' after parameter list");
|
|
9251
9252
|
}
|
|
9252
9253
|
const bodyCommands = this.parseCommandBlock(['end', 'catch', 'finally']);
|
|
9254
|
+
const { errorSymbol, errorHandler, finallyHandler } = this.parseErrorAndFinallyBlocks();
|
|
9255
|
+
this.consume('end', "Expected 'end' after function definition");
|
|
9256
|
+
return {
|
|
9257
|
+
type: 'def',
|
|
9258
|
+
name: funcName,
|
|
9259
|
+
params,
|
|
9260
|
+
body: bodyCommands,
|
|
9261
|
+
...(errorSymbol !== undefined && { errorSymbol }),
|
|
9262
|
+
...(errorHandler !== undefined && { errorHandler }),
|
|
9263
|
+
...(finallyHandler !== undefined && { finallyHandler }),
|
|
9264
|
+
start: pos.start,
|
|
9265
|
+
end: this.getPosition().end,
|
|
9266
|
+
line: pos.line,
|
|
9267
|
+
column: pos.column,
|
|
9268
|
+
};
|
|
9269
|
+
}
|
|
9270
|
+
parseErrorAndFinallyBlocks() {
|
|
9253
9271
|
let errorSymbol;
|
|
9254
9272
|
let errorHandler;
|
|
9255
9273
|
if (this.check('catch')) {
|
|
@@ -9264,19 +9282,10 @@ class Parser {
|
|
|
9264
9282
|
this.advance();
|
|
9265
9283
|
finallyHandler = this.parseCommandBlock(['end']);
|
|
9266
9284
|
}
|
|
9267
|
-
this.consume('end', "Expected 'end' after function definition");
|
|
9268
9285
|
return {
|
|
9269
|
-
type: 'def',
|
|
9270
|
-
name: funcName,
|
|
9271
|
-
params,
|
|
9272
|
-
body: bodyCommands,
|
|
9273
9286
|
...(errorSymbol !== undefined && { errorSymbol }),
|
|
9274
9287
|
...(errorHandler !== undefined && { errorHandler }),
|
|
9275
9288
|
...(finallyHandler !== undefined && { finallyHandler }),
|
|
9276
|
-
start: pos.start,
|
|
9277
|
-
end: this.getPosition().end,
|
|
9278
|
-
line: pos.line,
|
|
9279
|
-
column: pos.column,
|
|
9280
9289
|
};
|
|
9281
9290
|
}
|
|
9282
9291
|
parseEventNameWithNamespace(errorMessage) {
|
|
@@ -9421,13 +9430,13 @@ class Parser {
|
|
|
9421
9430
|
try {
|
|
9422
9431
|
const cmd = this.parseCommand();
|
|
9423
9432
|
if (this.error && this.error !== savedError) {
|
|
9424
|
-
debug.parse('
|
|
9433
|
+
debug.parse('\u26a0\ufe0f Command parsing added error, restoring error state. Error was:', this.error.message);
|
|
9425
9434
|
this.error = savedError;
|
|
9426
9435
|
}
|
|
9427
9436
|
return cmd;
|
|
9428
9437
|
}
|
|
9429
9438
|
catch (error) {
|
|
9430
|
-
debug.parse('
|
|
9439
|
+
debug.parse('\u26a0\ufe0f Command parsing threw exception, restoring error state:', error instanceof Error ? error.message : String(error));
|
|
9431
9440
|
this.error = savedError;
|
|
9432
9441
|
return null;
|
|
9433
9442
|
}
|
|
@@ -9444,12 +9453,12 @@ class Parser {
|
|
|
9444
9453
|
const timeToken = this.advance();
|
|
9445
9454
|
const delayMs = parseTimeToMs(timeToken.value);
|
|
9446
9455
|
modifiers[modifierKey] = delayMs;
|
|
9447
|
-
debug.parse(
|
|
9456
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed '${modName} at ${timeToken.value}' (${delayMs}ms)`);
|
|
9448
9457
|
}
|
|
9449
9458
|
else if (this.matchNumber()) {
|
|
9450
9459
|
const delayMs = parseInt(this.previous().value, 10);
|
|
9451
9460
|
modifiers[modifierKey] = delayMs;
|
|
9452
|
-
debug.parse(
|
|
9461
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed '${modName} at ${delayMs}'`);
|
|
9453
9462
|
}
|
|
9454
9463
|
else {
|
|
9455
9464
|
this.addError(`Expected time expression after '${modName} at', got: ${this.peek().value}`);
|
|
@@ -9460,7 +9469,7 @@ class Parser {
|
|
|
9460
9469
|
}
|
|
9461
9470
|
}
|
|
9462
9471
|
parseEventHandler() {
|
|
9463
|
-
debug.parse(
|
|
9472
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: ENTRY - parsing event handler`);
|
|
9464
9473
|
const eventNames = [];
|
|
9465
9474
|
let firstOnceAlias = false;
|
|
9466
9475
|
if (this.check('first') && !this.checkIsCommand() && this.current + 1 < this.tokens.length) {
|
|
@@ -9469,27 +9478,27 @@ class Parser {
|
|
|
9469
9478
|
if (peek2Value && peek2Value !== 'of' && peek2Value !== 'in' && peek2Value !== 'from') {
|
|
9470
9479
|
this.advance();
|
|
9471
9480
|
firstOnceAlias = true;
|
|
9472
|
-
debug.parse(
|
|
9481
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'first' as .once alias`);
|
|
9473
9482
|
}
|
|
9474
9483
|
}
|
|
9475
9484
|
const event = this.parseEventNameWithNamespace("Expected event name after 'on'");
|
|
9476
9485
|
eventNames.push(event);
|
|
9477
|
-
debug.parse(
|
|
9486
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed first event name: ${event}`);
|
|
9478
9487
|
while (this.check('or')) {
|
|
9479
9488
|
this.advance();
|
|
9480
|
-
debug.parse(
|
|
9489
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Found 'or', parsing additional event name`);
|
|
9481
9490
|
const additionalEvent = this.parseEventNameWithNamespace("Expected event name after 'or'");
|
|
9482
9491
|
eventNames.push(additionalEvent);
|
|
9483
|
-
debug.parse(
|
|
9492
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed additional event name: ${additionalEvent}`);
|
|
9484
9493
|
}
|
|
9485
|
-
debug.parse(
|
|
9494
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Total events parsed: ${eventNames.join(', ')}`);
|
|
9486
9495
|
let customEventSource;
|
|
9487
9496
|
if (this.registryIntegration) {
|
|
9488
9497
|
const firstEvent = eventNames[0];
|
|
9489
9498
|
if (this.registryIntegration.hasEventSource(firstEvent)) {
|
|
9490
9499
|
const source = this.registryIntegration.getEventSource(firstEvent);
|
|
9491
9500
|
customEventSource = source?.name;
|
|
9492
|
-
debug.parse(
|
|
9501
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Detected custom event source '${customEventSource}' for event '${firstEvent}'`);
|
|
9493
9502
|
}
|
|
9494
9503
|
}
|
|
9495
9504
|
const eventParams = [];
|
|
@@ -9501,7 +9510,7 @@ class Parser {
|
|
|
9501
9510
|
} while (this.match(','));
|
|
9502
9511
|
}
|
|
9503
9512
|
this.consume(')', "Expected ')' after event parameters");
|
|
9504
|
-
debug.parse(
|
|
9513
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed event parameters: ${eventParams.join(', ')}`);
|
|
9505
9514
|
}
|
|
9506
9515
|
const modifiers = {};
|
|
9507
9516
|
while (this.check('.')) {
|
|
@@ -9510,15 +9519,15 @@ class Parser {
|
|
|
9510
9519
|
const modName = modToken.value.toLowerCase();
|
|
9511
9520
|
if (modName === 'once') {
|
|
9512
9521
|
modifiers.once = true;
|
|
9513
|
-
debug.parse(
|
|
9522
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.once'`);
|
|
9514
9523
|
}
|
|
9515
9524
|
else if (modName === 'prevent') {
|
|
9516
9525
|
modifiers.prevent = true;
|
|
9517
|
-
debug.parse(
|
|
9526
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.prevent'`);
|
|
9518
9527
|
}
|
|
9519
9528
|
else if (modName === 'stop') {
|
|
9520
9529
|
modifiers.stop = true;
|
|
9521
|
-
debug.parse(
|
|
9530
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.stop'`);
|
|
9522
9531
|
}
|
|
9523
9532
|
else if (modName === 'debounce' || modName === 'throttle') {
|
|
9524
9533
|
if (this.check('(')) {
|
|
@@ -9530,11 +9539,11 @@ class Parser {
|
|
|
9530
9539
|
}
|
|
9531
9540
|
if (modName === 'debounce') {
|
|
9532
9541
|
modifiers.debounce = delayMs;
|
|
9533
|
-
debug.parse(
|
|
9542
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.debounce(${delayMs})'`);
|
|
9534
9543
|
}
|
|
9535
9544
|
else {
|
|
9536
9545
|
modifiers.throttle = delayMs;
|
|
9537
|
-
debug.parse(
|
|
9546
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.throttle(${delayMs})'`);
|
|
9538
9547
|
}
|
|
9539
9548
|
this.consume(')', `Expected ')' after ${modName} delay`);
|
|
9540
9549
|
}
|
|
@@ -9543,7 +9552,7 @@ class Parser {
|
|
|
9543
9552
|
}
|
|
9544
9553
|
}
|
|
9545
9554
|
else {
|
|
9546
|
-
debug.parse(
|
|
9555
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Warning - unknown modifier '.${modName}'`);
|
|
9547
9556
|
}
|
|
9548
9557
|
}
|
|
9549
9558
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
@@ -9551,7 +9560,7 @@ class Parser {
|
|
|
9551
9560
|
modifiers.once = true;
|
|
9552
9561
|
}
|
|
9553
9562
|
if (Object.keys(modifiers).length > 0) {
|
|
9554
|
-
debug.parse(
|
|
9563
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifiers:`, modifiers);
|
|
9555
9564
|
}
|
|
9556
9565
|
let condition;
|
|
9557
9566
|
if (this.match('[')) {
|
|
@@ -9562,7 +9571,7 @@ class Parser {
|
|
|
9562
9571
|
if (this.match('from')) {
|
|
9563
9572
|
const targetToken = this.advance();
|
|
9564
9573
|
target = targetToken.value;
|
|
9565
|
-
debug.parse(
|
|
9574
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'from' target: ${target} (kind: ${targetToken.kind})`);
|
|
9566
9575
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
9567
9576
|
}
|
|
9568
9577
|
let attributeName;
|
|
@@ -9574,32 +9583,36 @@ class Parser {
|
|
|
9574
9583
|
else {
|
|
9575
9584
|
attributeName = attrToken.value;
|
|
9576
9585
|
}
|
|
9577
|
-
debug.parse(
|
|
9586
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed attribute name: ${attributeName}`);
|
|
9578
9587
|
}
|
|
9579
9588
|
let watchTarget;
|
|
9580
9589
|
if (this.match('in')) {
|
|
9581
|
-
debug.parse(
|
|
9590
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Found 'in' keyword, parsing watch target`);
|
|
9582
9591
|
watchTarget = this.parseExpression();
|
|
9583
|
-
debug.parse(
|
|
9592
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed watch target expression`);
|
|
9584
9593
|
}
|
|
9585
9594
|
const commands = [];
|
|
9586
|
-
debug.parse(
|
|
9595
|
+
debug.parse(`\u2705 parseEventHandler: About to parse commands, current token: ${this.isAtEnd() ? 'END' : this.peek().value}, isAtEnd: ${this.isAtEnd()}`);
|
|
9587
9596
|
while (!this.isAtEnd()) {
|
|
9588
|
-
debug.parse(
|
|
9597
|
+
debug.parse(`\u2705 parseEventHandler: Loop iteration, current token: ${this.peek().value}, kind: ${this.peek().kind}`);
|
|
9589
9598
|
if (this.check('on')) {
|
|
9590
|
-
debug.parse(
|
|
9599
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found next event handler 'on'`);
|
|
9591
9600
|
break;
|
|
9592
9601
|
}
|
|
9593
9602
|
if (this.checkComment()) {
|
|
9594
|
-
debug.parse(
|
|
9603
|
+
debug.parse(`\u2705 parseEventHandler: Skipping comment token: ${this.peek().value}`);
|
|
9595
9604
|
this.advance();
|
|
9596
9605
|
continue;
|
|
9597
9606
|
}
|
|
9598
9607
|
if (this.check('end')) {
|
|
9599
|
-
debug.parse(
|
|
9608
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found 'end' keyword`);
|
|
9600
9609
|
this.advance();
|
|
9601
9610
|
break;
|
|
9602
9611
|
}
|
|
9612
|
+
if (this.check('catch') || this.check('finally')) {
|
|
9613
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found '${this.peek().value}'`);
|
|
9614
|
+
break;
|
|
9615
|
+
}
|
|
9603
9616
|
if (this.checkIsCommand()) {
|
|
9604
9617
|
const nextIsOpenParen = this.tokens[this.current + 1]?.value === '(';
|
|
9605
9618
|
const commandName = this.peek().value.toLowerCase();
|
|
@@ -9628,7 +9641,7 @@ class Parser {
|
|
|
9628
9641
|
const cmd = this.parseCommandWithErrorRecovery();
|
|
9629
9642
|
if (cmd) {
|
|
9630
9643
|
commands.push(cmd);
|
|
9631
|
-
debug.parse(
|
|
9644
|
+
debug.parse(`\u2705 parseEventHandler: Parsed command, next token: ${this.isAtEnd() ? 'END' : this.peek().value}`);
|
|
9632
9645
|
}
|
|
9633
9646
|
}
|
|
9634
9647
|
}
|
|
@@ -9646,7 +9659,7 @@ class Parser {
|
|
|
9646
9659
|
expr = this.parseExpression();
|
|
9647
9660
|
}
|
|
9648
9661
|
catch (error) {
|
|
9649
|
-
debug.parse('
|
|
9662
|
+
debug.parse('\u26a0\ufe0f Expression parsing error, restoring error state:', error instanceof Error ? error.message : String(error));
|
|
9650
9663
|
this.error = savedError;
|
|
9651
9664
|
break;
|
|
9652
9665
|
}
|
|
@@ -9693,7 +9706,9 @@ class Parser {
|
|
|
9693
9706
|
!this.check('then') &&
|
|
9694
9707
|
!this.check('and') &&
|
|
9695
9708
|
!this.check(',') &&
|
|
9696
|
-
!this.check('on')
|
|
9709
|
+
!this.check('on') &&
|
|
9710
|
+
!this.check('catch') &&
|
|
9711
|
+
!this.check('finally')) {
|
|
9697
9712
|
this.advance();
|
|
9698
9713
|
}
|
|
9699
9714
|
if (this.match('then', 'and', ',')) {
|
|
@@ -9706,12 +9721,24 @@ class Parser {
|
|
|
9706
9721
|
break;
|
|
9707
9722
|
}
|
|
9708
9723
|
}
|
|
9724
|
+
let errorSymbol;
|
|
9725
|
+
let errorHandler;
|
|
9726
|
+
let finallyHandler;
|
|
9727
|
+
if (!this.isAtEnd() && (this.check('catch') || this.check('finally'))) {
|
|
9728
|
+
({ errorSymbol, errorHandler, finallyHandler } = this.parseErrorAndFinallyBlocks());
|
|
9729
|
+
if (this.check('end')) {
|
|
9730
|
+
this.advance();
|
|
9731
|
+
}
|
|
9732
|
+
}
|
|
9709
9733
|
const pos = this.getPosition();
|
|
9710
9734
|
const node = {
|
|
9711
9735
|
type: 'eventHandler',
|
|
9712
9736
|
event: eventNames.length === 1 ? eventNames[0] : eventNames.join('|'),
|
|
9713
9737
|
events: eventNames,
|
|
9714
9738
|
commands,
|
|
9739
|
+
...(errorSymbol !== undefined && { errorSymbol }),
|
|
9740
|
+
...(errorHandler !== undefined && { errorHandler }),
|
|
9741
|
+
...(finallyHandler !== undefined && { finallyHandler }),
|
|
9715
9742
|
...(eventParams.length > 0 && { args: eventParams }),
|
|
9716
9743
|
...(condition && { condition }),
|
|
9717
9744
|
...(target && { target }),
|
|
@@ -9724,7 +9751,7 @@ class Parser {
|
|
|
9724
9751
|
line: pos.line,
|
|
9725
9752
|
column: pos.column,
|
|
9726
9753
|
};
|
|
9727
|
-
debug.parse(
|
|
9754
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Created node with events: ${eventNames.join(', ')}, attributeName: ${attributeName || 'none'}, watchTarget: ${watchTarget ? 'yes' : 'none'}`);
|
|
9728
9755
|
return node;
|
|
9729
9756
|
}
|
|
9730
9757
|
parseBehaviorDefinition() {
|
|
@@ -9789,11 +9816,33 @@ class Parser {
|
|
|
9789
9816
|
}
|
|
9790
9817
|
}
|
|
9791
9818
|
}
|
|
9792
|
-
const handlerCommands = this.
|
|
9819
|
+
const { commands: handlerCommands, terminator } = this.parseCommandListUntilTerminator([
|
|
9820
|
+
'catch',
|
|
9821
|
+
'finally',
|
|
9822
|
+
]);
|
|
9823
|
+
let handlerErrorSymbol;
|
|
9824
|
+
let handlerErrorHandler;
|
|
9825
|
+
let handlerFinallyHandler;
|
|
9826
|
+
if (terminator === 'catch' || terminator === 'finally') {
|
|
9827
|
+
({
|
|
9828
|
+
errorSymbol: handlerErrorSymbol,
|
|
9829
|
+
errorHandler: handlerErrorHandler,
|
|
9830
|
+
finallyHandler: handlerFinallyHandler,
|
|
9831
|
+
} = this.parseErrorAndFinallyBlocks());
|
|
9832
|
+
}
|
|
9833
|
+
if (this.check('end')) {
|
|
9834
|
+
this.advance();
|
|
9835
|
+
}
|
|
9836
|
+
else {
|
|
9837
|
+
throw new Error('Expected "end" to close behavior event handler');
|
|
9838
|
+
}
|
|
9793
9839
|
const handlerNode = {
|
|
9794
9840
|
type: 'eventHandler',
|
|
9795
9841
|
event: eventName,
|
|
9796
9842
|
commands: handlerCommands,
|
|
9843
|
+
...(handlerErrorSymbol !== undefined && { errorSymbol: handlerErrorSymbol }),
|
|
9844
|
+
...(handlerErrorHandler !== undefined && { errorHandler: handlerErrorHandler }),
|
|
9845
|
+
...(handlerFinallyHandler !== undefined && { finallyHandler: handlerFinallyHandler }),
|
|
9797
9846
|
...(eventSource !== undefined && { target: eventSource }),
|
|
9798
9847
|
...(eventArgs.length > 0 && { args: eventArgs }),
|
|
9799
9848
|
start: handlerPos.start,
|
|
@@ -9848,7 +9897,7 @@ class Parser {
|
|
|
9848
9897
|
this.error.message.includes('unclosed parenthes') ||
|
|
9849
9898
|
this.error.message.includes('Unclosed parenthes');
|
|
9850
9899
|
if (!isCriticalError) {
|
|
9851
|
-
debug.parse('
|
|
9900
|
+
debug.parse('\u26a0\ufe0f parseCommandSequence: Command parsing added non-critical error, restoring error state. Error was:', this.error.message);
|
|
9852
9901
|
this.error = savedError;
|
|
9853
9902
|
}
|
|
9854
9903
|
}
|
|
@@ -9858,11 +9907,11 @@ class Parser {
|
|
|
9858
9907
|
!this.isCommand(this.peek().value) &&
|
|
9859
9908
|
!this.check('then') &&
|
|
9860
9909
|
!this.check('on')) {
|
|
9861
|
-
debug.parse('
|
|
9910
|
+
debug.parse('\u26a0\ufe0f parseCommandSequence: Skipping unexpected token:', this.peek().value);
|
|
9862
9911
|
this.advance();
|
|
9863
9912
|
}
|
|
9864
9913
|
if (this.check('on')) {
|
|
9865
|
-
debug.parse('
|
|
9914
|
+
debug.parse('\u2705 parseCommandSequence: Found "on" token, stopping command sequence to allow event handler parsing');
|
|
9866
9915
|
break;
|
|
9867
9916
|
}
|
|
9868
9917
|
if (this.match('then')) {
|
|
@@ -10306,7 +10355,7 @@ class Parser {
|
|
|
10306
10355
|
if (!this.check(')') && callee.type === 'identifier') {
|
|
10307
10356
|
const funcName = callee.name;
|
|
10308
10357
|
if (CommandClassification.isCSSFunction(funcName)) {
|
|
10309
|
-
debug.parse(
|
|
10358
|
+
debug.parse(`\ud83d\udca1 Tip: CSS functions like ${funcName}() should be quoted for clean parsing. ` +
|
|
10310
10359
|
`Use '${funcName}(...)' or \`${funcName}(...)\` instead.`);
|
|
10311
10360
|
}
|
|
10312
10361
|
}
|
|
@@ -10608,7 +10657,7 @@ class Parser {
|
|
|
10608
10657
|
if (this.checkIsCommand() || (this.isCommand(token.value) && !this.isKeyword(token.value))) {
|
|
10609
10658
|
return;
|
|
10610
10659
|
}
|
|
10611
|
-
debug.parse('
|
|
10660
|
+
debug.parse('\u26a0\ufe0f synchronize: Skipping token:', token.value);
|
|
10612
10661
|
this.advance();
|
|
10613
10662
|
}
|
|
10614
10663
|
}
|