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