starlight-cli 1.0.47 → 1.0.49

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/src/parser.js CHANGED
@@ -83,10 +83,11 @@ class Parser {
83
83
  return this.expressionStatement();
84
84
  }
85
85
  }
86
-
87
- varDeclaration() {
86
+ varDeclaration() {
87
+ const t = this.current; // LET token
88
88
  this.eat('LET');
89
- const id = this.current.value;
89
+ const idToken = this.current; // identifier token
90
+ const id = idToken.value;
90
91
  this.eat('IDENTIFIER');
91
92
 
92
93
  let expr = null;
@@ -98,16 +99,30 @@ class Parser {
98
99
  // semicolon optional
99
100
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
100
101
 
101
- return { type: 'VarDeclaration', id, expr };
102
+ return {
103
+ type: 'VarDeclaration',
104
+ id,
105
+ expr,
106
+ line: t.line,
107
+ column: t.column
108
+ };
102
109
  }
103
110
 
104
111
  sldeployStatement() {
112
+ const t = this.current; // SLDEPLOY token
105
113
  this.eat('SLDEPLOY');
106
114
  const expr = this.expression();
107
115
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
108
- return { type: 'SldeployStatement', expr };
116
+ return {
117
+ type: 'SldeployStatement',
118
+ expr,
119
+ line: t.line,
120
+ column: t.column
121
+ };
109
122
  }
123
+
110
124
  doTrackStatement() {
125
+ const t = this.current; // DO token
111
126
  this.eat('DO');
112
127
 
113
128
  const body = this.block();
@@ -121,13 +136,17 @@ doTrackStatement() {
121
136
  return {
122
137
  type: 'DoTrackStatement',
123
138
  body,
124
- handler
139
+ handler,
140
+ line: t.line,
141
+ column: t.column
125
142
  };
126
143
  }
127
144
 
128
145
  defineStatement() {
146
+ const t = this.current; // DEFINE token
129
147
  this.eat('DEFINE');
130
- const id = this.current.value;
148
+ const idToken = this.current; // identifier token
149
+ const id = idToken.value;
131
150
  this.eat('IDENTIFIER');
132
151
 
133
152
  let expr = null;
@@ -138,10 +157,17 @@ defineStatement() {
138
157
 
139
158
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
140
159
 
141
- return { type: 'DefineStatement', id, expr };
160
+ return {
161
+ type: 'DefineStatement',
162
+ id,
163
+ expr,
164
+ line: t.line,
165
+ column: t.column
166
+ };
142
167
  }
143
168
 
144
169
  asyncFuncDeclaration() {
170
+ const t = this.current; // first token of function (identifier)
145
171
  const name = this.current.value;
146
172
  this.eat('IDENTIFIER');
147
173
 
@@ -167,10 +193,19 @@ asyncFuncDeclaration() {
167
193
  }
168
194
 
169
195
  const body = this.block();
170
- return { type: 'FunctionDeclaration', name, params, body, async: true };
196
+ return {
197
+ type: 'FunctionDeclaration',
198
+ name,
199
+ params,
200
+ body,
201
+ async: true,
202
+ line: t.line,
203
+ column: t.column
204
+ };
171
205
  }
172
206
 
173
207
  ifStatement() {
208
+ const t = this.current; // IF token
174
209
  this.eat('IF');
175
210
 
176
211
  let test;
@@ -179,7 +214,7 @@ ifStatement() {
179
214
  test = this.expression();
180
215
  this.eat('RPAREN');
181
216
  } else {
182
- // python style: no parentheses
217
+ // Python style: no parentheses
183
218
  test = this.expression();
184
219
  }
185
220
 
@@ -192,10 +227,18 @@ ifStatement() {
192
227
  else alternate = this.block();
193
228
  }
194
229
 
195
- return { type: 'IfStatement', test, consequent, alternate };
230
+ return {
231
+ type: 'IfStatement',
232
+ test,
233
+ consequent,
234
+ alternate,
235
+ line: t.line,
236
+ column: t.column
237
+ };
196
238
  }
197
239
 
198
240
  whileStatement() {
241
+ const t = this.current; // WHILE token
199
242
  this.eat('WHILE');
200
243
 
201
244
  let test;
@@ -208,10 +251,17 @@ whileStatement() {
208
251
  }
209
252
 
210
253
  const body = this.block();
211
- return { type: 'WhileStatement', test, body };
254
+ return {
255
+ type: 'WhileStatement',
256
+ test,
257
+ body,
258
+ line: t.line,
259
+ column: t.column
260
+ };
212
261
  }
213
262
 
214
263
  importStatement() {
264
+ const t = this.current; // IMPORT token
215
265
  this.eat('IMPORT');
216
266
 
217
267
  let specifiers = [];
@@ -220,11 +270,13 @@ importStatement() {
220
270
  this.eat('AS');
221
271
  const name = this.current.value;
222
272
  this.eat('IDENTIFIER');
223
- specifiers.push({ type: 'NamespaceImport', local: name });
273
+ specifiers.push({ type: 'NamespaceImport', local: name, line: t.line, column: t.column });
224
274
  } else if (this.current.type === 'LBRACE') {
225
275
  this.eat('LBRACE');
226
276
  while (this.current.type !== 'RBRACE') {
227
277
  const importedName = this.current.value;
278
+ const importedLine = this.current.line;
279
+ const importedColumn = this.current.column;
228
280
  this.eat('IDENTIFIER');
229
281
 
230
282
  let localName = importedName;
@@ -234,14 +286,16 @@ importStatement() {
234
286
  this.eat('IDENTIFIER');
235
287
  }
236
288
 
237
- specifiers.push({ type: 'NamedImport', imported: importedName, local: localName });
289
+ specifiers.push({ type: 'NamedImport', imported: importedName, local: localName, line: importedLine, column: importedColumn });
238
290
  if (this.current.type === 'COMMA') this.eat('COMMA');
239
291
  }
240
292
  this.eat('RBRACE');
241
293
  } else if (this.current.type === 'IDENTIFIER') {
242
294
  const localName = this.current.value;
295
+ const localLine = this.current.line;
296
+ const localColumn = this.current.column;
243
297
  this.eat('IDENTIFIER');
244
- specifiers.push({ type: 'DefaultImport', local: localName });
298
+ specifiers.push({ type: 'DefaultImport', local: localName, line: localLine, column: localColumn });
245
299
  } else {
246
300
  throw new Error(`Unexpected token in import at line ${this.current.line}, column ${this.current.column}`);
247
301
  }
@@ -253,9 +307,17 @@ importStatement() {
253
307
 
254
308
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
255
309
 
256
- return { type: 'ImportStatement', path: pathToken.value, specifiers };
310
+ return {
311
+ type: 'ImportStatement',
312
+ path: pathToken.value,
313
+ specifiers,
314
+ line: t.line,
315
+ column: t.column
316
+ };
257
317
  }
318
+
258
319
  forStatement() {
320
+ const t = this.current; // FOR token
259
321
  this.eat('FOR');
260
322
 
261
323
  // --- Python-style: for variable in iterable (supports optional 'let') ---
@@ -263,17 +325,22 @@ forStatement() {
263
325
  (this.current.type === 'IDENTIFIER' && this.peekType() === 'IN')) {
264
326
 
265
327
  let variable;
328
+ let variableLine, variableColumn;
266
329
  let iterable;
267
330
  let letKeyword = false;
268
331
 
269
332
  if (this.current.type === 'LET') {
270
333
  letKeyword = true;
271
334
  this.eat('LET');
335
+ variableLine = this.current.line;
336
+ variableColumn = this.current.column;
272
337
  variable = this.current.value;
273
338
  this.eat('IDENTIFIER');
274
339
  this.eat('IN');
275
340
  iterable = this.expression();
276
341
  } else {
342
+ variableLine = this.current.line;
343
+ variableColumn = this.current.column;
277
344
  variable = this.current.value;
278
345
  this.eat('IDENTIFIER');
279
346
  this.eat('IN');
@@ -281,7 +348,17 @@ forStatement() {
281
348
  }
282
349
 
283
350
  const body = this.block();
284
- return { type: 'ForInStatement', variable, iterable, letKeyword, body };
351
+ return {
352
+ type: 'ForInStatement',
353
+ variable,
354
+ variableLine,
355
+ variableColumn,
356
+ iterable,
357
+ letKeyword,
358
+ body,
359
+ line: t.line,
360
+ column: t.column
361
+ };
285
362
  }
286
363
 
287
364
  // --- C-style: for(init; test; update) ---
@@ -316,37 +393,51 @@ forStatement() {
316
393
  }
317
394
 
318
395
  const body = this.block();
319
- return { type: 'ForStatement', init, test, update, body };
396
+ return {
397
+ type: 'ForStatement',
398
+ init,
399
+ test,
400
+ update,
401
+ body,
402
+ line: t.line,
403
+ column: t.column
404
+ };
320
405
  }
321
406
 
322
407
  breakStatement() {
408
+ const t = this.current; // BREAK token
323
409
  this.eat('BREAK');
324
410
  // Python-style: no semicolon needed, ignore if present
325
411
  if (this.current.type === 'SEMICOLON') this.advance();
326
- return { type: 'BreakStatement' };
412
+ return { type: 'BreakStatement', line: t.line, column: t.column };
327
413
  }
328
414
 
329
415
  continueStatement() {
416
+ const t = this.current; // CONTINUE token
330
417
  this.eat('CONTINUE');
331
418
  // Python-style: no semicolon needed, ignore if present
332
419
  if (this.current.type === 'SEMICOLON') this.advance();
333
- return { type: 'ContinueStatement' };
420
+ return { type: 'ContinueStatement', line: t.line, column: t.column };
334
421
  }
335
422
 
336
423
  funcDeclaration() {
424
+ const t = this.current; // FUNC token
337
425
  this.eat('FUNC');
338
- const name = this.current.value;
426
+ const nameToken = this.current;
427
+ const name = nameToken.value;
339
428
  this.eat('IDENTIFIER');
340
429
 
341
430
  let params = [];
342
431
  if (this.current.type === 'LPAREN') {
343
432
  this.eat('LPAREN');
344
433
  if (this.current.type !== 'RPAREN') {
345
- params.push(this.current.value);
434
+ const paramToken = this.current;
435
+ params.push({ name: paramToken.value, line: paramToken.line, column: paramToken.column });
346
436
  this.eat('IDENTIFIER');
347
437
  while (this.current.type === 'COMMA') {
348
438
  this.eat('COMMA');
349
- params.push(this.current.value);
439
+ const paramToken2 = this.current;
440
+ params.push({ name: paramToken2.value, line: paramToken2.line, column: paramToken2.column });
350
441
  this.eat('IDENTIFIER');
351
442
  }
352
443
  }
@@ -354,16 +445,18 @@ funcDeclaration() {
354
445
  } else {
355
446
  // Python-style: single param without parentheses
356
447
  if (this.current.type === 'IDENTIFIER') {
357
- params.push(this.current.value);
448
+ const paramToken = this.current;
449
+ params.push({ name: paramToken.value, line: paramToken.line, column: paramToken.column });
358
450
  this.eat('IDENTIFIER');
359
451
  }
360
452
  }
361
453
 
362
454
  const body = this.block();
363
- return { type: 'FunctionDeclaration', name, params, body };
455
+ return { type: 'FunctionDeclaration', name, params, body, line: t.line, column: t.column };
364
456
  }
365
457
 
366
458
  returnStatement() {
459
+ const t = this.current; // RETURN token
367
460
  this.eat('RETURN');
368
461
 
369
462
  let argument = null;
@@ -374,24 +467,26 @@ returnStatement() {
374
467
  // semicolon optional
375
468
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
376
469
 
377
- return { type: 'ReturnStatement', argument };
470
+ return { type: 'ReturnStatement', argument, line: t.line, column: t.column };
378
471
  }
379
472
 
380
473
  block() {
474
+ const t = this.current; // LBRACE token
381
475
  this.eat('LBRACE');
382
476
  const body = [];
383
477
  while (this.current.type !== 'RBRACE') {
384
478
  body.push(this.statement());
385
479
  }
386
480
  this.eat('RBRACE');
387
- return { type: 'BlockStatement', body };
481
+ return { type: 'BlockStatement', body, line: t.line, column: t.column };
388
482
  }
389
483
 
390
484
  expressionStatement() {
485
+ const exprToken = this.current; // first token of the expression
391
486
  const expr = this.expression();
392
487
  // semicolon optional
393
488
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
394
- return { type: 'ExpressionStatement', expression: expr };
489
+ return { type: 'ExpressionStatement', expression: expr, line: exprToken.line, column: exprToken.column };
395
490
  }
396
491
 
397
492
  expression() {
@@ -402,17 +497,19 @@ assignment() {
402
497
  const node = this.logicalOr();
403
498
  const compoundOps = ['PLUSEQ', 'MINUSEQ', 'STAREQ', 'SLASHEQ', 'MODEQ'];
404
499
 
405
- if (compoundOps.includes(this.current.type)) {
406
- const op = this.current.type;
500
+ const t = this.current;
501
+
502
+ if (compoundOps.includes(t.type)) {
503
+ const op = t.type;
407
504
  this.eat(op);
408
505
  const right = this.assignment();
409
- return { type: 'CompoundAssignment', operator: op, left: node, right };
506
+ return { type: 'CompoundAssignment', operator: op, left: node, right, line: t.line, column: t.column };
410
507
  }
411
508
 
412
- if (this.current.type === 'EQUAL') {
509
+ if (t.type === 'EQUAL') {
413
510
  this.eat('EQUAL');
414
511
  const right = this.assignment();
415
- return { type: 'AssignmentExpression', left: node, right };
512
+ return { type: 'AssignmentExpression', left: node, right, line: t.line, column: t.column };
416
513
  }
417
514
 
418
515
  return node;
@@ -421,9 +518,10 @@ assignment() {
421
518
  logicalOr() {
422
519
  let node = this.logicalAnd();
423
520
  while (this.current.type === 'OR') {
424
- const op = this.current.type;
521
+ const t = this.current;
522
+ const op = t.type;
425
523
  this.eat(op);
426
- node = { type: 'LogicalExpression', operator: op, left: node, right: this.logicalAnd() };
524
+ node = { type: 'LogicalExpression', operator: op, left: node, right: this.logicalAnd(), line: t.line, column: t.column };
427
525
  }
428
526
  return node;
429
527
  }
@@ -431,18 +529,21 @@ logicalOr() {
431
529
  logicalAnd() {
432
530
  let node = this.equality();
433
531
  while (this.current.type === 'AND') {
434
- const op = this.current.type;
532
+ const t = this.current;
533
+ const op = t.type;
435
534
  this.eat(op);
436
- node = { type: 'LogicalExpression', operator: op, left: node, right: this.equality() };
535
+ node = { type: 'LogicalExpression', operator: op, left: node, right: this.equality(), line: t.line, column: t.column };
437
536
  }
438
537
  return node;
439
538
  }
539
+
440
540
  equality() {
441
541
  let node = this.comparison();
442
542
  while (['EQEQ', 'NOTEQ'].includes(this.current.type)) {
443
- const op = this.current.type;
543
+ const t = this.current;
544
+ const op = t.type;
444
545
  this.eat(op);
445
- node = { type: 'BinaryExpression', operator: op, left: node, right: this.comparison() };
546
+ node = { type: 'BinaryExpression', operator: op, left: node, right: this.comparison(), line: t.line, column: t.column };
446
547
  }
447
548
  return node;
448
549
  }
@@ -450,9 +551,10 @@ equality() {
450
551
  comparison() {
451
552
  let node = this.term();
452
553
  while (['LT', 'LTE', 'GT', 'GTE'].includes(this.current.type)) {
453
- const op = this.current.type;
554
+ const t = this.current;
555
+ const op = t.type;
454
556
  this.eat(op);
455
- node = { type: 'BinaryExpression', operator: op, left: node, right: this.term() };
557
+ node = { type: 'BinaryExpression', operator: op, left: node, right: this.term(), line: t.line, column: t.column };
456
558
  }
457
559
  return node;
458
560
  }
@@ -460,9 +562,10 @@ comparison() {
460
562
  term() {
461
563
  let node = this.factor();
462
564
  while (['PLUS', 'MINUS'].includes(this.current.type)) {
463
- const op = this.current.type;
565
+ const t = this.current;
566
+ const op = t.type;
464
567
  this.eat(op);
465
- node = { type: 'BinaryExpression', operator: op, left: node, right: this.factor() };
568
+ node = { type: 'BinaryExpression', operator: op, left: node, right: this.factor(), line: t.line, column: t.column };
466
569
  }
467
570
  return node;
468
571
  }
@@ -470,26 +573,43 @@ term() {
470
573
  factor() {
471
574
  let node = this.unary();
472
575
  while (['STAR', 'SLASH', 'MOD'].includes(this.current.type)) {
473
- const op = this.current.type;
576
+ const t = this.current;
577
+ const op = t.type;
474
578
  this.eat(op);
475
- node = { type: 'BinaryExpression', operator: op, left: node, right: this.unary() };
579
+ node = { type: 'BinaryExpression', operator: op, left: node, right: this.unary(), line: t.line, column: t.column };
476
580
  }
477
581
  return node;
478
582
  }
479
583
 
584
+
480
585
  unary() {
481
- if (['NOT', 'MINUS', 'PLUS'].includes(this.current.type)) {
482
- const op = this.current.type;
586
+ const t = this.current;
587
+
588
+ if (['NOT', 'MINUS', 'PLUS'].includes(t.type)) {
589
+ const op = t.type;
483
590
  this.eat(op);
484
- return { type: 'UnaryExpression', operator: op, argument: this.unary() };
591
+ return {
592
+ type: 'UnaryExpression',
593
+ operator: op,
594
+ argument: this.unary(),
595
+ line: t.line,
596
+ column: t.column
597
+ };
485
598
  }
486
599
 
487
600
  // Python-like: ignore ++ and -- if not used
488
- if (this.current.type === 'PLUSPLUS' || this.current.type === 'MINUSMINUS') {
489
- const op = this.current.type;
601
+ if (t.type === 'PLUSPLUS' || t.type === 'MINUSMINUS') {
602
+ const op = t.type;
490
603
  this.eat(op);
491
604
  const argument = this.unary();
492
- return { type: 'UpdateExpression', operator: op, argument, prefix: true };
605
+ return {
606
+ type: 'UpdateExpression',
607
+ operator: op,
608
+ argument,
609
+ prefix: true,
610
+ line: t.line,
611
+ column: t.column
612
+ };
493
613
  }
494
614
 
495
615
  return this.postfix();
@@ -498,15 +618,21 @@ unary() {
498
618
  postfix() {
499
619
  let node = this.primary();
500
620
  while (true) {
501
- if (this.current.type === 'LBRACKET') {
621
+ const t = this.current;
622
+
623
+ if (t.type === 'LBRACKET') {
624
+ const startLine = t.line;
625
+ const startCol = t.column;
502
626
  this.eat('LBRACKET');
503
627
  const index = this.expression();
504
628
  if (this.current.type === 'RBRACKET') this.eat('RBRACKET');
505
- node = { type: 'IndexExpression', object: node, indexer: index };
629
+ node = { type: 'IndexExpression', object: node, indexer: index, line: startLine, column: startCol };
506
630
  continue;
507
631
  }
508
632
 
509
- if (this.current.type === 'LPAREN') {
633
+ if (t.type === 'LPAREN') {
634
+ const startLine = t.line;
635
+ const startCol = t.column;
510
636
  this.eat('LPAREN');
511
637
  const args = [];
512
638
  while (this.current.type !== 'RPAREN' && this.current.type !== 'EOF') {
@@ -514,30 +640,30 @@ postfix() {
514
640
  if (this.current.type === 'COMMA') this.eat('COMMA'); // optional comma
515
641
  }
516
642
  if (this.current.type === 'RPAREN') this.eat('RPAREN');
517
- node = { type: 'CallExpression', callee: node, arguments: args };
643
+ node = { type: 'CallExpression', callee: node, arguments: args, line: startLine, column: startCol };
518
644
  continue;
519
645
  }
520
646
 
521
- if (this.current.type === 'DOT') {
647
+ if (t.type === 'DOT') {
648
+ const startLine = t.line;
649
+ const startCol = t.column;
522
650
  this.eat('DOT');
523
651
  const property = this.current.value || '';
524
652
  if (this.current.type === 'IDENTIFIER') this.eat('IDENTIFIER');
525
- node = { type: 'MemberExpression', object: node, property };
653
+ node = { type: 'MemberExpression', object: node, property, line: startLine, column: startCol };
526
654
  continue;
527
655
  }
528
656
 
529
- if (this.current.type === 'PLUSPLUS' || this.current.type === 'MINUSMINUS') {
530
- const op = this.current.type;
531
- this.eat(op);
532
- node = { type: 'UpdateExpression', operator: op, argument: node, prefix: false };
657
+ if (t.type === 'PLUSPLUS' || t.type === 'MINUSMINUS') {
658
+ this.eat(t.type);
659
+ node = { type: 'UpdateExpression', operator: t.type, argument: node, prefix: false, line: t.line, column: t.column };
533
660
  continue;
534
661
  }
535
662
 
536
- // Python-style: implicit function calls (if identifier followed by identifier)
537
- if (node.type === 'Identifier' && this.current.type === 'IDENTIFIER') {
538
- const argNode = { type: 'Identifier', name: this.current.value };
663
+ if (node.type === 'Identifier' && t.type === 'IDENTIFIER') {
664
+ const argNode = { type: 'Identifier', name: t.value, line: t.line, column: t.column };
539
665
  this.eat('IDENTIFIER');
540
- node = { type: 'CallExpression', callee: node, arguments: [argNode] };
666
+ node = { type: 'CallExpression', callee: node, arguments: [argNode], line: node.line, column: node.column };
541
667
  continue;
542
668
  }
543
669
 
@@ -547,12 +673,18 @@ postfix() {
547
673
  }
548
674
 
549
675
  arrowFunction(params) {
550
- if (this.current.type === 'ARROW') this.eat('ARROW');
676
+ const t = this.current;
677
+ if (t.type === 'ARROW') this.eat('ARROW');
551
678
  const body = this.expression();
679
+ const startLine = params.length > 0 ? params[0].line : t.line;
680
+ const startCol = params.length > 0 ? params[0].column : t.column;
681
+
552
682
  return {
553
683
  type: 'ArrowFunctionExpression',
554
684
  params,
555
- body
685
+ body,
686
+ line: startLine,
687
+ column: startCol
556
688
  };
557
689
  }
558
690
 
@@ -560,16 +692,35 @@ arrowFunction(params) {
560
692
  primary() {
561
693
  const t = this.current;
562
694
 
563
- if (t.type === 'NUMBER') { this.eat('NUMBER'); return { type: 'Literal', value: t.value }; }
564
- if (t.type === 'STRING') { this.eat('STRING'); return { type: 'Literal', value: t.value }; }
565
- if (t.type === 'TRUE') { this.eat('TRUE'); return { type: 'Literal', value: true }; }
566
- if (t.type === 'FALSE') { this.eat('FALSE'); return { type: 'Literal', value: false }; }
567
- if (t.type === 'NULL') { this.eat('NULL'); return { type: 'Literal', value: null }; }
695
+ if (t.type === 'NUMBER') {
696
+ this.eat('NUMBER');
697
+ return { type: 'Literal', value: t.value, line: t.line, column: t.column };
698
+ }
699
+
700
+ if (t.type === 'STRING') {
701
+ this.eat('STRING');
702
+ return { type: 'Literal', value: t.value, line: t.line, column: t.column };
703
+ }
704
+
705
+ if (t.type === 'TRUE') {
706
+ this.eat('TRUE');
707
+ return { type: 'Literal', value: true, line: t.line, column: t.column };
708
+ }
709
+
710
+ if (t.type === 'FALSE') {
711
+ this.eat('FALSE');
712
+ return { type: 'Literal', value: false, line: t.line, column: t.column };
713
+ }
714
+
715
+ if (t.type === 'NULL') {
716
+ this.eat('NULL');
717
+ return { type: 'Literal', value: null, line: t.line, column: t.column };
718
+ }
568
719
 
569
720
  if (t.type === 'AWAIT') {
570
721
  this.eat('AWAIT');
571
722
  const argument = this.expression();
572
- return { type: 'AwaitExpression', argument };
723
+ return { type: 'AwaitExpression', argument, line: t.line, column: t.column };
573
724
  }
574
725
 
575
726
  if (t.type === 'NEW') {
@@ -585,7 +736,7 @@ arrowFunction(params) {
585
736
  }
586
737
  }
587
738
  this.eat('RPAREN');
588
- return { type: 'NewExpression', callee, arguments: args };
739
+ return { type: 'NewExpression', callee, arguments: args, line: t.line, column: t.column };
589
740
  }
590
741
 
591
742
  if (t.type === 'ASK') {
@@ -600,7 +751,13 @@ arrowFunction(params) {
600
751
  }
601
752
  }
602
753
  this.eat('RPAREN');
603
- return { type: 'CallExpression', callee: { type: 'Identifier', name: 'ask' }, arguments: args };
754
+ return {
755
+ type: 'CallExpression',
756
+ callee: { type: 'Identifier', name: 'ask', line: t.line, column: t.column },
757
+ arguments: args,
758
+ line: t.line,
759
+ column: t.column
760
+ };
604
761
  }
605
762
 
606
763
  if (t.type === 'IDENTIFIER') {
@@ -608,13 +765,15 @@ arrowFunction(params) {
608
765
  this.eat('IDENTIFIER');
609
766
 
610
767
  if (this.current.type === 'ARROW') {
611
- return this.arrowFunction([name]);
768
+ return this.arrowFunction([{ type: 'Identifier', name, line: t.line, column: t.column }]);
612
769
  }
613
770
 
614
- return { type: 'Identifier', name };
771
+ return { type: 'Identifier', name, line: t.line, column: t.column };
615
772
  }
616
773
 
617
774
  if (t.type === 'LPAREN') {
775
+ const startLine = t.line;
776
+ const startCol = t.column;
618
777
  this.eat('LPAREN');
619
778
  const elements = [];
620
779
 
@@ -630,10 +789,12 @@ arrowFunction(params) {
630
789
 
631
790
  if (this.current.type === 'ARROW') return this.arrowFunction(elements);
632
791
 
633
- return elements.length === 1 ? elements[0] : { type: 'ArrayExpression', elements };
792
+ return elements.length === 1 ? elements[0] : { type: 'ArrayExpression', elements, line: startLine, column: startCol };
634
793
  }
635
794
 
636
795
  if (t.type === 'LBRACKET') {
796
+ const startLine = t.line;
797
+ const startCol = t.column;
637
798
  this.eat('LBRACKET');
638
799
  const elements = [];
639
800
  if (this.current.type !== 'RBRACKET') {
@@ -644,10 +805,12 @@ arrowFunction(params) {
644
805
  }
645
806
  }
646
807
  this.eat('RBRACKET');
647
- return { type: 'ArrayExpression', elements };
808
+ return { type: 'ArrayExpression', elements, line: startLine, column: startCol };
648
809
  }
649
810
 
650
811
  if (t.type === 'LBRACE') {
812
+ const startLine = t.line;
813
+ const startCol = t.column;
651
814
  this.eat('LBRACE');
652
815
  const props = [];
653
816
  while (this.current.type !== 'RBRACE') {
@@ -658,17 +821,17 @@ arrowFunction(params) {
658
821
  if (this.current.type === 'COMMA') this.eat('COMMA'); // optional trailing comma
659
822
  }
660
823
  this.eat('RBRACE');
661
- return { type: 'ObjectExpression', props };
824
+ return { type: 'ObjectExpression', props, line: startLine, column: startCol };
662
825
  }
663
826
 
664
827
  throw new ParseError(
665
- `Unexpected token '${t.type}'`,
666
- t,
667
- this.source
668
- );
669
-
828
+ `Unexpected token '${t.type}'`,
829
+ t,
830
+ this.source
831
+ );
670
832
  }
671
833
 
834
+
672
835
  }
673
836
 
674
837
  module.exports = Parser;