@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
|
@@ -422,6 +422,7 @@ function tokenize(input) {
|
|
|
422
422
|
const prevToken = tokenizer.tokens[tokenizer.tokens.length - 1];
|
|
423
423
|
const isPossessive = nextChar === 's' &&
|
|
424
424
|
prevToken &&
|
|
425
|
+
!/\s/.test(tokenizer.input[tokenizer.position - 1] ?? ' ') &&
|
|
425
426
|
(prevToken.kind === TokenKind.IDENTIFIER ||
|
|
426
427
|
prevToken.kind === TokenKind.SELECTOR ||
|
|
427
428
|
prevToken.value === ']' ||
|
|
@@ -1294,39 +1295,39 @@ const DEBUG = {
|
|
|
1294
1295
|
const debug = {
|
|
1295
1296
|
command: (...args) => {
|
|
1296
1297
|
if (DEBUG.commands)
|
|
1297
|
-
console.log('
|
|
1298
|
+
console.log('\ud83d\udd27', ...args);
|
|
1298
1299
|
},
|
|
1299
1300
|
event: (...args) => {
|
|
1300
1301
|
if (DEBUG.events)
|
|
1301
|
-
console.log('
|
|
1302
|
+
console.log('\ud83c\udfaf', ...args);
|
|
1302
1303
|
},
|
|
1303
1304
|
parse: (...args) => {
|
|
1304
1305
|
if (DEBUG.parsing)
|
|
1305
|
-
console.log('
|
|
1306
|
+
console.log('\ud83d\udcdd', ...args);
|
|
1306
1307
|
},
|
|
1307
1308
|
expr: (...args) => {
|
|
1308
1309
|
if (DEBUG.expressions)
|
|
1309
|
-
console.log('
|
|
1310
|
+
console.log('\ud83d\udd0d', ...args);
|
|
1310
1311
|
},
|
|
1311
1312
|
expressions: (...args) => {
|
|
1312
1313
|
if (DEBUG.expressions)
|
|
1313
|
-
console.log('
|
|
1314
|
+
console.log('\ud83d\udd0d', ...args);
|
|
1314
1315
|
},
|
|
1315
1316
|
style: (...args) => {
|
|
1316
1317
|
if (DEBUG.styles)
|
|
1317
|
-
console.log('
|
|
1318
|
+
console.log('\ud83c\udfa8', ...args);
|
|
1318
1319
|
},
|
|
1319
1320
|
runtime: (...args) => {
|
|
1320
1321
|
if (DEBUG.runtime)
|
|
1321
|
-
console.log('
|
|
1322
|
+
console.log('\ud83d\ude80', ...args);
|
|
1322
1323
|
},
|
|
1323
1324
|
loop: (...args) => {
|
|
1324
1325
|
if (DEBUG.loops)
|
|
1325
|
-
console.log('
|
|
1326
|
+
console.log('\ud83d\udd01', ...args);
|
|
1326
1327
|
},
|
|
1327
1328
|
async: (...args) => {
|
|
1328
1329
|
if (DEBUG.async)
|
|
1329
|
-
console.log('
|
|
1330
|
+
console.log('\u23f3', ...args);
|
|
1330
1331
|
},
|
|
1331
1332
|
};
|
|
1332
1333
|
|
|
@@ -2724,9 +2725,9 @@ function createPartialCommandNode(name, pos) {
|
|
|
2724
2725
|
};
|
|
2725
2726
|
}
|
|
2726
2727
|
function createProgramNode(statements) {
|
|
2727
|
-
debug.parse(
|
|
2728
|
+
debug.parse(`\u2705 createProgramNode: Called with ${statements.length} statements`);
|
|
2728
2729
|
if (statements.length === 0) {
|
|
2729
|
-
debug.parse(
|
|
2730
|
+
debug.parse(`\u2705 createProgramNode: Returning error node (0 statements)`);
|
|
2730
2731
|
return {
|
|
2731
2732
|
type: 'identifier',
|
|
2732
2733
|
name: '__ERROR__',
|
|
@@ -2737,7 +2738,7 @@ function createProgramNode(statements) {
|
|
|
2737
2738
|
};
|
|
2738
2739
|
}
|
|
2739
2740
|
if (statements.length === 1) {
|
|
2740
|
-
debug.parse(
|
|
2741
|
+
debug.parse(`\u2705 createProgramNode: Returning single statement (type=${statements[0].type})`);
|
|
2741
2742
|
return statements[0];
|
|
2742
2743
|
}
|
|
2743
2744
|
const programNode = {
|
|
@@ -2748,7 +2749,7 @@ function createProgramNode(statements) {
|
|
|
2748
2749
|
line: statements[0]?.line || 1,
|
|
2749
2750
|
column: statements[0]?.column || 1,
|
|
2750
2751
|
};
|
|
2751
|
-
debug.parse(
|
|
2752
|
+
debug.parse(`\u2705 createProgramNode: Returning Program node with ${statements.length} statements, type=${programNode.type}`);
|
|
2752
2753
|
return programNode;
|
|
2753
2754
|
}
|
|
2754
2755
|
|
|
@@ -3137,37 +3138,37 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
3137
3138
|
ctx.advance();
|
|
3138
3139
|
loopType = 'until-event';
|
|
3139
3140
|
const eventToken = ctx.peek();
|
|
3140
|
-
debug.parse('
|
|
3141
|
+
debug.parse('\ud83d\udccd Parsing event name, current token:', {
|
|
3141
3142
|
value: eventToken.value,
|
|
3142
3143
|
kind: eventToken.kind,
|
|
3143
3144
|
});
|
|
3144
3145
|
if (isIdentifierLike(eventToken) || isEvent(eventToken)) {
|
|
3145
3146
|
eventName = eventToken.value;
|
|
3146
3147
|
ctx.advance();
|
|
3147
|
-
debug.parse('
|
|
3148
|
+
debug.parse('\u2705 Got event name:', eventName, 'Next token:', ctx.peek().value);
|
|
3148
3149
|
}
|
|
3149
3150
|
else {
|
|
3150
3151
|
throw new Error('Expected event name after "event"');
|
|
3151
3152
|
}
|
|
3152
|
-
debug.parse('
|
|
3153
|
+
debug.parse('\ud83d\udd0d Checking for "from", current token:', ctx.peek().value);
|
|
3153
3154
|
if (ctx.check(KEYWORDS.FROM)) {
|
|
3154
|
-
debug.parse('
|
|
3155
|
+
debug.parse('\u2705 Found "from", advancing...');
|
|
3155
3156
|
ctx.advance();
|
|
3156
|
-
debug.parse('
|
|
3157
|
+
debug.parse('\ud83d\udccd After consuming "from", current token:', ctx.peek().value);
|
|
3157
3158
|
if (consumeOptionalKeyword(ctx, KEYWORDS.THE)) {
|
|
3158
|
-
debug.parse('
|
|
3159
|
+
debug.parse('\u2705 Found "the", advancing...');
|
|
3159
3160
|
}
|
|
3160
3161
|
const beforePrimary = ctx.peek();
|
|
3161
|
-
debug.parse('
|
|
3162
|
+
debug.parse('\ud83d\udd0d Before parsePrimary for event target:', {
|
|
3162
3163
|
value: beforePrimary.value,
|
|
3163
3164
|
kind: beforePrimary.kind,
|
|
3164
3165
|
position: beforePrimary.start,
|
|
3165
3166
|
});
|
|
3166
3167
|
eventTarget = ctx.parsePrimary();
|
|
3167
|
-
debug.parse('
|
|
3168
|
+
debug.parse('\u2705 After parsePrimary, eventTarget:', eventTarget);
|
|
3168
3169
|
}
|
|
3169
3170
|
else {
|
|
3170
|
-
debug.parse('
|
|
3171
|
+
debug.parse('\u274c No "from" found, skipping target parsing');
|
|
3171
3172
|
}
|
|
3172
3173
|
}
|
|
3173
3174
|
else {
|
|
@@ -4268,16 +4269,6 @@ function stringNode(value, tok) {
|
|
|
4268
4269
|
column: tok.column,
|
|
4269
4270
|
};
|
|
4270
4271
|
}
|
|
4271
|
-
function isNakedURLStart(ctx) {
|
|
4272
|
-
const tok = ctx.peek();
|
|
4273
|
-
if (tok.value === '/')
|
|
4274
|
-
return true;
|
|
4275
|
-
if (ctx.checkIdentifierLike()) {
|
|
4276
|
-
const next = ctx.peekAt(1);
|
|
4277
|
-
return !!next && next.value === ':' && next.start === tok.end;
|
|
4278
|
-
}
|
|
4279
|
-
return false;
|
|
4280
|
-
}
|
|
4281
4272
|
function parseGoCommand(ctx, identifierNode) {
|
|
4282
4273
|
const args = [];
|
|
4283
4274
|
while (!isCommandBoundary(ctx, ['when', 'where', 'catch', 'finally'])) {
|
|
@@ -4436,6 +4427,16 @@ function isFetchURLTerminator(ctx) {
|
|
|
4436
4427
|
return (['as', 'with', '{', 'then', 'end', 'else', 'otherwise', ')'].includes(val) ||
|
|
4437
4428
|
isCommandBoundary(ctx));
|
|
4438
4429
|
}
|
|
4430
|
+
function isNakedURLStart(ctx) {
|
|
4431
|
+
const tok = ctx.peek();
|
|
4432
|
+
if (tok.value === '/')
|
|
4433
|
+
return true;
|
|
4434
|
+
if (ctx.checkIdentifierLike()) {
|
|
4435
|
+
const next = ctx.peekAt(1);
|
|
4436
|
+
return !!next && next.value === ':' && next.start === tok.end;
|
|
4437
|
+
}
|
|
4438
|
+
return false;
|
|
4439
|
+
}
|
|
4439
4440
|
function parseBareURLPath(ctx, isTerminator = isFetchURLTerminator) {
|
|
4440
4441
|
const startPos = ctx.savePosition();
|
|
4441
4442
|
let path = '';
|
|
@@ -4457,7 +4458,7 @@ function parseBareURLPath(ctx, isTerminator = isFetchURLTerminator) {
|
|
|
4457
4458
|
function parseFetchCommand(ctx, commandToken) {
|
|
4458
4459
|
const modifiers = {};
|
|
4459
4460
|
let url = null;
|
|
4460
|
-
if (!ctx.isAtEnd() && ctx
|
|
4461
|
+
if (!ctx.isAtEnd() && isNakedURLStart(ctx)) {
|
|
4461
4462
|
url = parseBareURLPath(ctx);
|
|
4462
4463
|
}
|
|
4463
4464
|
if (!url) {
|
|
@@ -5023,26 +5024,26 @@ class Parser {
|
|
|
5023
5024
|
const commandSequence = this.parseCommandSequence();
|
|
5024
5025
|
if (commandSequence) {
|
|
5025
5026
|
if (!this.isAtEnd() && this.check('on')) {
|
|
5026
|
-
debug.parse('
|
|
5027
|
+
debug.parse('\u2705 PARSER: Found event handlers after command sequence, parsing as program');
|
|
5027
5028
|
const statements = [commandSequence];
|
|
5028
|
-
debug.parse(
|
|
5029
|
+
debug.parse(`\u2705 PARSER: Starting with ${statements.length} statement(s) from command sequence`);
|
|
5029
5030
|
let eventHandlerCount = 0;
|
|
5030
5031
|
while (!this.isAtEnd() && this.check('on')) {
|
|
5031
|
-
debug.parse(
|
|
5032
|
+
debug.parse(`\u2705 PARSER: Parsing event handler #${eventHandlerCount + 1}, current token: ${this.peek().value}`);
|
|
5032
5033
|
this.advance();
|
|
5033
5034
|
const eventHandler = this.parseEventHandler();
|
|
5034
|
-
debug.parse(
|
|
5035
|
+
debug.parse(`\u2705 PARSER: parseEventHandler returned:`, eventHandler
|
|
5035
5036
|
? `type=${eventHandler.type}, event=${eventHandler.event}`
|
|
5036
5037
|
: 'null');
|
|
5037
5038
|
if (eventHandler) {
|
|
5038
5039
|
statements.push(eventHandler);
|
|
5039
5040
|
eventHandlerCount++;
|
|
5040
|
-
debug.parse(
|
|
5041
|
+
debug.parse(`\u2705 PARSER: Added event handler, now have ${statements.length} statements total`);
|
|
5041
5042
|
}
|
|
5042
|
-
debug.parse(
|
|
5043
|
+
debug.parse(`\u2705 PARSER: After parsing event handler, current token: ${this.isAtEnd() ? 'END' : this.peek().value}, isAtEnd=${this.isAtEnd()}, check('on')=${this.check('on')}`);
|
|
5043
5044
|
if (!this.isAtEnd() && !this.check('on')) {
|
|
5044
5045
|
if (!this.isAtEnd()) {
|
|
5045
|
-
debug.parse(
|
|
5046
|
+
debug.parse(`\u26a0\ufe0f PARSER: Unexpected token after event handlers: ${this.peek().value}`);
|
|
5046
5047
|
this.addError(`Unexpected token after event handlers: ${this.peek().value}`);
|
|
5047
5048
|
return {
|
|
5048
5049
|
success: false,
|
|
@@ -5051,11 +5052,11 @@ class Parser {
|
|
|
5051
5052
|
error: this.error,
|
|
5052
5053
|
};
|
|
5053
5054
|
}
|
|
5054
|
-
debug.parse(
|
|
5055
|
+
debug.parse(`\u2705 PARSER: No more event handlers, at end of input`);
|
|
5055
5056
|
break;
|
|
5056
5057
|
}
|
|
5057
5058
|
}
|
|
5058
|
-
debug.parse(
|
|
5059
|
+
debug.parse(`\u2705 PARSER: Finished parsing, creating Program node with ${statements.length} statements`);
|
|
5059
5060
|
if (this.error) {
|
|
5060
5061
|
return {
|
|
5061
5062
|
success: false,
|
|
@@ -5450,41 +5451,41 @@ class Parser {
|
|
|
5450
5451
|
parseCommandListUntilTerminator(extraStops) {
|
|
5451
5452
|
const commands = [];
|
|
5452
5453
|
const isStop = () => this.check('end') || extraStops.some(s => this.check(s));
|
|
5453
|
-
debug.parse('
|
|
5454
|
+
debug.parse('\ud83d\udd04 parseCommandListUntilTerminator: Starting (extraStops:', extraStops.join(','), ')');
|
|
5454
5455
|
while (!this.isAtEnd() && !isStop()) {
|
|
5455
|
-
debug.parse('
|
|
5456
|
+
debug.parse('\ud83d\udccd Loop iteration, current token:', this.peek().value, 'kind:', this.peek().kind);
|
|
5456
5457
|
let parsedCommand = false;
|
|
5457
5458
|
const isCommandToken = this.checkIsCommand();
|
|
5458
5459
|
const isCommandIdentifier = !isCommandToken && this.checkIdentifier() && this.isCommand(this.peek().value);
|
|
5459
5460
|
if (isCommandToken || isCommandIdentifier) {
|
|
5460
|
-
debug.parse(isCommandToken ? '
|
|
5461
|
+
debug.parse(isCommandToken ? '\u2705 Found COMMAND token:' : '\u2705 Found IDENTIFIER that is a command:', this.peek().value);
|
|
5461
5462
|
this.advance();
|
|
5462
5463
|
const savedError = this.error;
|
|
5463
5464
|
try {
|
|
5464
5465
|
const cmd = this.parseCommand();
|
|
5465
5466
|
if (this.error && this.error !== savedError) {
|
|
5466
|
-
debug.parse('
|
|
5467
|
+
debug.parse('\u26a0\ufe0f parseCommandListUntilTerminator: Command parsing added error, restoring. Error was:', this.error.message);
|
|
5467
5468
|
this.error = savedError;
|
|
5468
5469
|
}
|
|
5469
5470
|
if (cmd) {
|
|
5470
|
-
debug.parse('
|
|
5471
|
+
debug.parse('\u2705 Parsed command:', cmd.name);
|
|
5471
5472
|
commands.push(cmd);
|
|
5472
5473
|
parsedCommand = true;
|
|
5473
5474
|
}
|
|
5474
5475
|
}
|
|
5475
5476
|
catch (error) {
|
|
5476
|
-
debug.parse('
|
|
5477
|
+
debug.parse('\u26a0\ufe0f parseCommandListUntilTerminator: Command parsing threw, restoring:', error instanceof Error ? error.message : String(error));
|
|
5477
5478
|
this.error = savedError;
|
|
5478
5479
|
}
|
|
5479
5480
|
}
|
|
5480
5481
|
else if (this.checkIdentifier()) {
|
|
5481
|
-
debug.parse('
|
|
5482
|
+
debug.parse('\u274c IDENTIFIER is not a command:', this.peek().value);
|
|
5482
5483
|
}
|
|
5483
5484
|
if (!parsedCommand) {
|
|
5484
|
-
debug.parse('
|
|
5485
|
+
debug.parse('\u274c No command parsed, breaking. Current token:', this.peek().value);
|
|
5485
5486
|
break;
|
|
5486
5487
|
}
|
|
5487
|
-
debug.parse('
|
|
5488
|
+
debug.parse('\ud83d\udccd After parsing command, current token:', this.peek().value);
|
|
5488
5489
|
while (!this.isAtEnd() &&
|
|
5489
5490
|
!isStop() &&
|
|
5490
5491
|
!this.checkIsCommand() &&
|
|
@@ -5492,19 +5493,19 @@ class Parser {
|
|
|
5492
5493
|
!this.check('then') &&
|
|
5493
5494
|
!this.check('and') &&
|
|
5494
5495
|
!this.check(',')) {
|
|
5495
|
-
debug.parse('
|
|
5496
|
+
debug.parse('\u26a0\ufe0f Skipping unexpected token:', this.peek().value);
|
|
5496
5497
|
this.advance();
|
|
5497
5498
|
}
|
|
5498
5499
|
if (this.match('then', 'and', ',')) {
|
|
5499
|
-
debug.parse('
|
|
5500
|
+
debug.parse('\u2705 Found separator, continuing');
|
|
5500
5501
|
continue;
|
|
5501
5502
|
}
|
|
5502
5503
|
else if (this.checkIsCommand() || this.isCommand(this.peek().value)) {
|
|
5503
|
-
debug.parse('
|
|
5504
|
+
debug.parse('\u2705 Next token is a command, continuing without separator');
|
|
5504
5505
|
continue;
|
|
5505
5506
|
}
|
|
5506
5507
|
else {
|
|
5507
|
-
debug.parse('
|
|
5508
|
+
debug.parse('\ud83d\udccd No separator and no command, breaking. Current token:', this.peek().value);
|
|
5508
5509
|
break;
|
|
5509
5510
|
}
|
|
5510
5511
|
}
|
|
@@ -5518,18 +5519,18 @@ class Parser {
|
|
|
5518
5519
|
if (!this.check('end') && !extraStops.some(s => this.check(s))) {
|
|
5519
5520
|
terminator = '';
|
|
5520
5521
|
}
|
|
5521
|
-
debug.parse('
|
|
5522
|
+
debug.parse('\u2705 parseCommandListUntilTerminator: parsed', commands.length, 'commands (terminator:', terminator, ')');
|
|
5522
5523
|
return { commands, terminator };
|
|
5523
5524
|
}
|
|
5524
5525
|
parseCommandListUntilEnd() {
|
|
5525
5526
|
const { commands } = this.parseCommandListUntilTerminator([]);
|
|
5526
|
-
debug.parse('
|
|
5527
|
+
debug.parse('\ud83d\udd0d After loop, checking for "end". Current token:', this.peek().value);
|
|
5527
5528
|
if (this.check('end')) {
|
|
5528
|
-
debug.parse('
|
|
5529
|
+
debug.parse('\u2705 Found "end", consuming it');
|
|
5529
5530
|
this.advance();
|
|
5530
5531
|
}
|
|
5531
5532
|
else {
|
|
5532
|
-
debug.parse('
|
|
5533
|
+
debug.parse('\u274c ERROR: Expected "end" but got:', this.peek().value, 'at position:', this.peek().start);
|
|
5533
5534
|
throw new Error('Expected "end" to close repeat block');
|
|
5534
5535
|
}
|
|
5535
5536
|
return commands;
|
|
@@ -6202,6 +6203,23 @@ class Parser {
|
|
|
6202
6203
|
this.consume(')', "Expected ')' after parameter list");
|
|
6203
6204
|
}
|
|
6204
6205
|
const bodyCommands = this.parseCommandBlock(['end', 'catch', 'finally']);
|
|
6206
|
+
const { errorSymbol, errorHandler, finallyHandler } = this.parseErrorAndFinallyBlocks();
|
|
6207
|
+
this.consume('end', "Expected 'end' after function definition");
|
|
6208
|
+
return {
|
|
6209
|
+
type: 'def',
|
|
6210
|
+
name: funcName,
|
|
6211
|
+
params,
|
|
6212
|
+
body: bodyCommands,
|
|
6213
|
+
...(errorSymbol !== undefined && { errorSymbol }),
|
|
6214
|
+
...(errorHandler !== undefined && { errorHandler }),
|
|
6215
|
+
...(finallyHandler !== undefined && { finallyHandler }),
|
|
6216
|
+
start: pos.start,
|
|
6217
|
+
end: this.getPosition().end,
|
|
6218
|
+
line: pos.line,
|
|
6219
|
+
column: pos.column,
|
|
6220
|
+
};
|
|
6221
|
+
}
|
|
6222
|
+
parseErrorAndFinallyBlocks() {
|
|
6205
6223
|
let errorSymbol;
|
|
6206
6224
|
let errorHandler;
|
|
6207
6225
|
if (this.check('catch')) {
|
|
@@ -6216,19 +6234,10 @@ class Parser {
|
|
|
6216
6234
|
this.advance();
|
|
6217
6235
|
finallyHandler = this.parseCommandBlock(['end']);
|
|
6218
6236
|
}
|
|
6219
|
-
this.consume('end', "Expected 'end' after function definition");
|
|
6220
6237
|
return {
|
|
6221
|
-
type: 'def',
|
|
6222
|
-
name: funcName,
|
|
6223
|
-
params,
|
|
6224
|
-
body: bodyCommands,
|
|
6225
6238
|
...(errorSymbol !== undefined && { errorSymbol }),
|
|
6226
6239
|
...(errorHandler !== undefined && { errorHandler }),
|
|
6227
6240
|
...(finallyHandler !== undefined && { finallyHandler }),
|
|
6228
|
-
start: pos.start,
|
|
6229
|
-
end: this.getPosition().end,
|
|
6230
|
-
line: pos.line,
|
|
6231
|
-
column: pos.column,
|
|
6232
6241
|
};
|
|
6233
6242
|
}
|
|
6234
6243
|
parseEventNameWithNamespace(errorMessage) {
|
|
@@ -6373,13 +6382,13 @@ class Parser {
|
|
|
6373
6382
|
try {
|
|
6374
6383
|
const cmd = this.parseCommand();
|
|
6375
6384
|
if (this.error && this.error !== savedError) {
|
|
6376
|
-
debug.parse('
|
|
6385
|
+
debug.parse('\u26a0\ufe0f Command parsing added error, restoring error state. Error was:', this.error.message);
|
|
6377
6386
|
this.error = savedError;
|
|
6378
6387
|
}
|
|
6379
6388
|
return cmd;
|
|
6380
6389
|
}
|
|
6381
6390
|
catch (error) {
|
|
6382
|
-
debug.parse('
|
|
6391
|
+
debug.parse('\u26a0\ufe0f Command parsing threw exception, restoring error state:', error instanceof Error ? error.message : String(error));
|
|
6383
6392
|
this.error = savedError;
|
|
6384
6393
|
return null;
|
|
6385
6394
|
}
|
|
@@ -6396,12 +6405,12 @@ class Parser {
|
|
|
6396
6405
|
const timeToken = this.advance();
|
|
6397
6406
|
const delayMs = parseTimeToMs(timeToken.value);
|
|
6398
6407
|
modifiers[modifierKey] = delayMs;
|
|
6399
|
-
debug.parse(
|
|
6408
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed '${modName} at ${timeToken.value}' (${delayMs}ms)`);
|
|
6400
6409
|
}
|
|
6401
6410
|
else if (this.matchNumber()) {
|
|
6402
6411
|
const delayMs = parseInt(this.previous().value, 10);
|
|
6403
6412
|
modifiers[modifierKey] = delayMs;
|
|
6404
|
-
debug.parse(
|
|
6413
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed '${modName} at ${delayMs}'`);
|
|
6405
6414
|
}
|
|
6406
6415
|
else {
|
|
6407
6416
|
this.addError(`Expected time expression after '${modName} at', got: ${this.peek().value}`);
|
|
@@ -6412,7 +6421,7 @@ class Parser {
|
|
|
6412
6421
|
}
|
|
6413
6422
|
}
|
|
6414
6423
|
parseEventHandler() {
|
|
6415
|
-
debug.parse(
|
|
6424
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: ENTRY - parsing event handler`);
|
|
6416
6425
|
const eventNames = [];
|
|
6417
6426
|
let firstOnceAlias = false;
|
|
6418
6427
|
if (this.check('first') && !this.checkIsCommand() && this.current + 1 < this.tokens.length) {
|
|
@@ -6421,27 +6430,27 @@ class Parser {
|
|
|
6421
6430
|
if (peek2Value && peek2Value !== 'of' && peek2Value !== 'in' && peek2Value !== 'from') {
|
|
6422
6431
|
this.advance();
|
|
6423
6432
|
firstOnceAlias = true;
|
|
6424
|
-
debug.parse(
|
|
6433
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'first' as .once alias`);
|
|
6425
6434
|
}
|
|
6426
6435
|
}
|
|
6427
6436
|
const event = this.parseEventNameWithNamespace("Expected event name after 'on'");
|
|
6428
6437
|
eventNames.push(event);
|
|
6429
|
-
debug.parse(
|
|
6438
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed first event name: ${event}`);
|
|
6430
6439
|
while (this.check('or')) {
|
|
6431
6440
|
this.advance();
|
|
6432
|
-
debug.parse(
|
|
6441
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Found 'or', parsing additional event name`);
|
|
6433
6442
|
const additionalEvent = this.parseEventNameWithNamespace("Expected event name after 'or'");
|
|
6434
6443
|
eventNames.push(additionalEvent);
|
|
6435
|
-
debug.parse(
|
|
6444
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed additional event name: ${additionalEvent}`);
|
|
6436
6445
|
}
|
|
6437
|
-
debug.parse(
|
|
6446
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Total events parsed: ${eventNames.join(', ')}`);
|
|
6438
6447
|
let customEventSource;
|
|
6439
6448
|
if (this.registryIntegration) {
|
|
6440
6449
|
const firstEvent = eventNames[0];
|
|
6441
6450
|
if (this.registryIntegration.hasEventSource(firstEvent)) {
|
|
6442
6451
|
const source = this.registryIntegration.getEventSource(firstEvent);
|
|
6443
6452
|
customEventSource = source?.name;
|
|
6444
|
-
debug.parse(
|
|
6453
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Detected custom event source '${customEventSource}' for event '${firstEvent}'`);
|
|
6445
6454
|
}
|
|
6446
6455
|
}
|
|
6447
6456
|
const eventParams = [];
|
|
@@ -6453,7 +6462,7 @@ class Parser {
|
|
|
6453
6462
|
} while (this.match(','));
|
|
6454
6463
|
}
|
|
6455
6464
|
this.consume(')', "Expected ')' after event parameters");
|
|
6456
|
-
debug.parse(
|
|
6465
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed event parameters: ${eventParams.join(', ')}`);
|
|
6457
6466
|
}
|
|
6458
6467
|
const modifiers = {};
|
|
6459
6468
|
while (this.check('.')) {
|
|
@@ -6462,15 +6471,15 @@ class Parser {
|
|
|
6462
6471
|
const modName = modToken.value.toLowerCase();
|
|
6463
6472
|
if (modName === 'once') {
|
|
6464
6473
|
modifiers.once = true;
|
|
6465
|
-
debug.parse(
|
|
6474
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.once'`);
|
|
6466
6475
|
}
|
|
6467
6476
|
else if (modName === 'prevent') {
|
|
6468
6477
|
modifiers.prevent = true;
|
|
6469
|
-
debug.parse(
|
|
6478
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.prevent'`);
|
|
6470
6479
|
}
|
|
6471
6480
|
else if (modName === 'stop') {
|
|
6472
6481
|
modifiers.stop = true;
|
|
6473
|
-
debug.parse(
|
|
6482
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.stop'`);
|
|
6474
6483
|
}
|
|
6475
6484
|
else if (modName === 'debounce' || modName === 'throttle') {
|
|
6476
6485
|
if (this.check('(')) {
|
|
@@ -6482,11 +6491,11 @@ class Parser {
|
|
|
6482
6491
|
}
|
|
6483
6492
|
if (modName === 'debounce') {
|
|
6484
6493
|
modifiers.debounce = delayMs;
|
|
6485
|
-
debug.parse(
|
|
6494
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.debounce(${delayMs})'`);
|
|
6486
6495
|
}
|
|
6487
6496
|
else {
|
|
6488
6497
|
modifiers.throttle = delayMs;
|
|
6489
|
-
debug.parse(
|
|
6498
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifier '.throttle(${delayMs})'`);
|
|
6490
6499
|
}
|
|
6491
6500
|
this.consume(')', `Expected ')' after ${modName} delay`);
|
|
6492
6501
|
}
|
|
@@ -6495,7 +6504,7 @@ class Parser {
|
|
|
6495
6504
|
}
|
|
6496
6505
|
}
|
|
6497
6506
|
else {
|
|
6498
|
-
debug.parse(
|
|
6507
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Warning - unknown modifier '.${modName}'`);
|
|
6499
6508
|
}
|
|
6500
6509
|
}
|
|
6501
6510
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
@@ -6503,7 +6512,7 @@ class Parser {
|
|
|
6503
6512
|
modifiers.once = true;
|
|
6504
6513
|
}
|
|
6505
6514
|
if (Object.keys(modifiers).length > 0) {
|
|
6506
|
-
debug.parse(
|
|
6515
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed modifiers:`, modifiers);
|
|
6507
6516
|
}
|
|
6508
6517
|
let condition;
|
|
6509
6518
|
if (this.match('[')) {
|
|
@@ -6514,7 +6523,7 @@ class Parser {
|
|
|
6514
6523
|
if (this.match('from')) {
|
|
6515
6524
|
const targetToken = this.advance();
|
|
6516
6525
|
target = targetToken.value;
|
|
6517
|
-
debug.parse(
|
|
6526
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'from' target: ${target} (kind: ${targetToken.kind})`);
|
|
6518
6527
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
6519
6528
|
}
|
|
6520
6529
|
let attributeName;
|
|
@@ -6526,32 +6535,36 @@ class Parser {
|
|
|
6526
6535
|
else {
|
|
6527
6536
|
attributeName = attrToken.value;
|
|
6528
6537
|
}
|
|
6529
|
-
debug.parse(
|
|
6538
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed attribute name: ${attributeName}`);
|
|
6530
6539
|
}
|
|
6531
6540
|
let watchTarget;
|
|
6532
6541
|
if (this.match('in')) {
|
|
6533
|
-
debug.parse(
|
|
6542
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Found 'in' keyword, parsing watch target`);
|
|
6534
6543
|
watchTarget = this.parseExpression();
|
|
6535
|
-
debug.parse(
|
|
6544
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed watch target expression`);
|
|
6536
6545
|
}
|
|
6537
6546
|
const commands = [];
|
|
6538
|
-
debug.parse(
|
|
6547
|
+
debug.parse(`\u2705 parseEventHandler: About to parse commands, current token: ${this.isAtEnd() ? 'END' : this.peek().value}, isAtEnd: ${this.isAtEnd()}`);
|
|
6539
6548
|
while (!this.isAtEnd()) {
|
|
6540
|
-
debug.parse(
|
|
6549
|
+
debug.parse(`\u2705 parseEventHandler: Loop iteration, current token: ${this.peek().value}, kind: ${this.peek().kind}`);
|
|
6541
6550
|
if (this.check('on')) {
|
|
6542
|
-
debug.parse(
|
|
6551
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found next event handler 'on'`);
|
|
6543
6552
|
break;
|
|
6544
6553
|
}
|
|
6545
6554
|
if (this.checkComment()) {
|
|
6546
|
-
debug.parse(
|
|
6555
|
+
debug.parse(`\u2705 parseEventHandler: Skipping comment token: ${this.peek().value}`);
|
|
6547
6556
|
this.advance();
|
|
6548
6557
|
continue;
|
|
6549
6558
|
}
|
|
6550
6559
|
if (this.check('end')) {
|
|
6551
|
-
debug.parse(
|
|
6560
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found 'end' keyword`);
|
|
6552
6561
|
this.advance();
|
|
6553
6562
|
break;
|
|
6554
6563
|
}
|
|
6564
|
+
if (this.check('catch') || this.check('finally')) {
|
|
6565
|
+
debug.parse(`\u2705 parseEventHandler: Stopping command parsing, found '${this.peek().value}'`);
|
|
6566
|
+
break;
|
|
6567
|
+
}
|
|
6555
6568
|
if (this.checkIsCommand()) {
|
|
6556
6569
|
const nextIsOpenParen = this.tokens[this.current + 1]?.value === '(';
|
|
6557
6570
|
const commandName = this.peek().value.toLowerCase();
|
|
@@ -6580,7 +6593,7 @@ class Parser {
|
|
|
6580
6593
|
const cmd = this.parseCommandWithErrorRecovery();
|
|
6581
6594
|
if (cmd) {
|
|
6582
6595
|
commands.push(cmd);
|
|
6583
|
-
debug.parse(
|
|
6596
|
+
debug.parse(`\u2705 parseEventHandler: Parsed command, next token: ${this.isAtEnd() ? 'END' : this.peek().value}`);
|
|
6584
6597
|
}
|
|
6585
6598
|
}
|
|
6586
6599
|
}
|
|
@@ -6598,7 +6611,7 @@ class Parser {
|
|
|
6598
6611
|
expr = this.parseExpression();
|
|
6599
6612
|
}
|
|
6600
6613
|
catch (error) {
|
|
6601
|
-
debug.parse('
|
|
6614
|
+
debug.parse('\u26a0\ufe0f Expression parsing error, restoring error state:', error instanceof Error ? error.message : String(error));
|
|
6602
6615
|
this.error = savedError;
|
|
6603
6616
|
break;
|
|
6604
6617
|
}
|
|
@@ -6645,7 +6658,9 @@ class Parser {
|
|
|
6645
6658
|
!this.check('then') &&
|
|
6646
6659
|
!this.check('and') &&
|
|
6647
6660
|
!this.check(',') &&
|
|
6648
|
-
!this.check('on')
|
|
6661
|
+
!this.check('on') &&
|
|
6662
|
+
!this.check('catch') &&
|
|
6663
|
+
!this.check('finally')) {
|
|
6649
6664
|
this.advance();
|
|
6650
6665
|
}
|
|
6651
6666
|
if (this.match('then', 'and', ',')) {
|
|
@@ -6658,12 +6673,24 @@ class Parser {
|
|
|
6658
6673
|
break;
|
|
6659
6674
|
}
|
|
6660
6675
|
}
|
|
6676
|
+
let errorSymbol;
|
|
6677
|
+
let errorHandler;
|
|
6678
|
+
let finallyHandler;
|
|
6679
|
+
if (!this.isAtEnd() && (this.check('catch') || this.check('finally'))) {
|
|
6680
|
+
({ errorSymbol, errorHandler, finallyHandler } = this.parseErrorAndFinallyBlocks());
|
|
6681
|
+
if (this.check('end')) {
|
|
6682
|
+
this.advance();
|
|
6683
|
+
}
|
|
6684
|
+
}
|
|
6661
6685
|
const pos = this.getPosition();
|
|
6662
6686
|
const node = {
|
|
6663
6687
|
type: 'eventHandler',
|
|
6664
6688
|
event: eventNames.length === 1 ? eventNames[0] : eventNames.join('|'),
|
|
6665
6689
|
events: eventNames,
|
|
6666
6690
|
commands,
|
|
6691
|
+
...(errorSymbol !== undefined && { errorSymbol }),
|
|
6692
|
+
...(errorHandler !== undefined && { errorHandler }),
|
|
6693
|
+
...(finallyHandler !== undefined && { finallyHandler }),
|
|
6667
6694
|
...(eventParams.length > 0 && { args: eventParams }),
|
|
6668
6695
|
...(condition && { condition }),
|
|
6669
6696
|
...(target && { target }),
|
|
@@ -6676,7 +6703,7 @@ class Parser {
|
|
|
6676
6703
|
line: pos.line,
|
|
6677
6704
|
column: pos.column,
|
|
6678
6705
|
};
|
|
6679
|
-
debug.parse(
|
|
6706
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Created node with events: ${eventNames.join(', ')}, attributeName: ${attributeName || 'none'}, watchTarget: ${watchTarget ? 'yes' : 'none'}`);
|
|
6680
6707
|
return node;
|
|
6681
6708
|
}
|
|
6682
6709
|
parseBehaviorDefinition() {
|
|
@@ -6741,11 +6768,33 @@ class Parser {
|
|
|
6741
6768
|
}
|
|
6742
6769
|
}
|
|
6743
6770
|
}
|
|
6744
|
-
const handlerCommands = this.
|
|
6771
|
+
const { commands: handlerCommands, terminator } = this.parseCommandListUntilTerminator([
|
|
6772
|
+
'catch',
|
|
6773
|
+
'finally',
|
|
6774
|
+
]);
|
|
6775
|
+
let handlerErrorSymbol;
|
|
6776
|
+
let handlerErrorHandler;
|
|
6777
|
+
let handlerFinallyHandler;
|
|
6778
|
+
if (terminator === 'catch' || terminator === 'finally') {
|
|
6779
|
+
({
|
|
6780
|
+
errorSymbol: handlerErrorSymbol,
|
|
6781
|
+
errorHandler: handlerErrorHandler,
|
|
6782
|
+
finallyHandler: handlerFinallyHandler,
|
|
6783
|
+
} = this.parseErrorAndFinallyBlocks());
|
|
6784
|
+
}
|
|
6785
|
+
if (this.check('end')) {
|
|
6786
|
+
this.advance();
|
|
6787
|
+
}
|
|
6788
|
+
else {
|
|
6789
|
+
throw new Error('Expected "end" to close behavior event handler');
|
|
6790
|
+
}
|
|
6745
6791
|
const handlerNode = {
|
|
6746
6792
|
type: 'eventHandler',
|
|
6747
6793
|
event: eventName,
|
|
6748
6794
|
commands: handlerCommands,
|
|
6795
|
+
...(handlerErrorSymbol !== undefined && { errorSymbol: handlerErrorSymbol }),
|
|
6796
|
+
...(handlerErrorHandler !== undefined && { errorHandler: handlerErrorHandler }),
|
|
6797
|
+
...(handlerFinallyHandler !== undefined && { finallyHandler: handlerFinallyHandler }),
|
|
6749
6798
|
...(eventSource !== undefined && { target: eventSource }),
|
|
6750
6799
|
...(eventArgs.length > 0 && { args: eventArgs }),
|
|
6751
6800
|
start: handlerPos.start,
|
|
@@ -6800,7 +6849,7 @@ class Parser {
|
|
|
6800
6849
|
this.error.message.includes('unclosed parenthes') ||
|
|
6801
6850
|
this.error.message.includes('Unclosed parenthes');
|
|
6802
6851
|
if (!isCriticalError) {
|
|
6803
|
-
debug.parse('
|
|
6852
|
+
debug.parse('\u26a0\ufe0f parseCommandSequence: Command parsing added non-critical error, restoring error state. Error was:', this.error.message);
|
|
6804
6853
|
this.error = savedError;
|
|
6805
6854
|
}
|
|
6806
6855
|
}
|
|
@@ -6810,11 +6859,11 @@ class Parser {
|
|
|
6810
6859
|
!this.isCommand(this.peek().value) &&
|
|
6811
6860
|
!this.check('then') &&
|
|
6812
6861
|
!this.check('on')) {
|
|
6813
|
-
debug.parse('
|
|
6862
|
+
debug.parse('\u26a0\ufe0f parseCommandSequence: Skipping unexpected token:', this.peek().value);
|
|
6814
6863
|
this.advance();
|
|
6815
6864
|
}
|
|
6816
6865
|
if (this.check('on')) {
|
|
6817
|
-
debug.parse('
|
|
6866
|
+
debug.parse('\u2705 parseCommandSequence: Found "on" token, stopping command sequence to allow event handler parsing');
|
|
6818
6867
|
break;
|
|
6819
6868
|
}
|
|
6820
6869
|
if (this.match('then')) {
|
|
@@ -7258,7 +7307,7 @@ class Parser {
|
|
|
7258
7307
|
if (!this.check(')') && callee.type === 'identifier') {
|
|
7259
7308
|
const funcName = callee.name;
|
|
7260
7309
|
if (CommandClassification.isCSSFunction(funcName)) {
|
|
7261
|
-
debug.parse(
|
|
7310
|
+
debug.parse(`\ud83d\udca1 Tip: CSS functions like ${funcName}() should be quoted for clean parsing. ` +
|
|
7262
7311
|
`Use '${funcName}(...)' or \`${funcName}(...)\` instead.`);
|
|
7263
7312
|
}
|
|
7264
7313
|
}
|
|
@@ -7560,7 +7609,7 @@ class Parser {
|
|
|
7560
7609
|
if (this.checkIsCommand() || (this.isCommand(token.value) && !this.isKeyword(token.value))) {
|
|
7561
7610
|
return;
|
|
7562
7611
|
}
|
|
7563
|
-
debug.parse('
|
|
7612
|
+
debug.parse('\u26a0\ufe0f synchronize: Skipping token:', token.value);
|
|
7564
7613
|
this.advance();
|
|
7565
7614
|
}
|
|
7566
7615
|
}
|