@tishlang/tish 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/Cargo.toml +2 -0
  2. package/README.md +2 -0
  3. package/bin/tish +0 -0
  4. package/crates/js_to_tish/src/error.rs +2 -8
  5. package/crates/js_to_tish/src/transform/expr.rs +128 -137
  6. package/crates/js_to_tish/src/transform/stmt.rs +62 -32
  7. package/crates/tish/Cargo.toml +15 -5
  8. package/crates/tish/src/cargo_native_registry.rs +29 -0
  9. package/crates/tish/src/cli_help.rs +92 -39
  10. package/crates/tish/src/main.rs +172 -86
  11. package/crates/tish/src/repl_completion.rs +3 -3
  12. package/crates/tish/tests/cargo_example_compile.rs +4 -2
  13. package/crates/tish/tests/integration_test.rs +216 -54
  14. package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
  15. package/crates/tish/tests/shortcircuit.rs +20 -5
  16. package/crates/tish_ast/src/ast.rs +92 -23
  17. package/crates/tish_build_utils/Cargo.toml +4 -0
  18. package/crates/tish_build_utils/src/lib.rs +136 -8
  19. package/crates/tish_builtins/Cargo.toml +5 -1
  20. package/crates/tish_builtins/src/array.rs +65 -33
  21. package/crates/tish_builtins/src/construct.rs +34 -39
  22. package/crates/tish_builtins/src/globals.rs +42 -26
  23. package/crates/tish_builtins/src/helpers.rs +2 -1
  24. package/crates/tish_builtins/src/lib.rs +5 -5
  25. package/crates/tish_builtins/src/math.rs +5 -3
  26. package/crates/tish_builtins/src/object.rs +3 -2
  27. package/crates/tish_builtins/src/string.rs +144 -22
  28. package/crates/tish_bytecode/src/chunk.rs +0 -1
  29. package/crates/tish_bytecode/src/compiler.rs +173 -71
  30. package/crates/tish_bytecode/src/opcode.rs +24 -6
  31. package/crates/tish_bytecode/src/peephole.rs +2 -2
  32. package/crates/tish_compile/Cargo.toml +1 -0
  33. package/crates/tish_compile/src/codegen.rs +1621 -453
  34. package/crates/tish_compile/src/infer.rs +75 -19
  35. package/crates/tish_compile/src/lib.rs +19 -8
  36. package/crates/tish_compile/src/resolve.rs +278 -137
  37. package/crates/tish_compile/src/types.rs +184 -24
  38. package/crates/tish_compile_js/Cargo.toml +1 -0
  39. package/crates/tish_compile_js/src/codegen.rs +181 -37
  40. package/crates/tish_compile_js/src/lib.rs +3 -1
  41. package/crates/tish_compile_js/src/tests_jsx.rs +30 -6
  42. package/crates/tish_compiler_wasm/src/lib.rs +16 -13
  43. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +69 -59
  44. package/crates/tish_core/Cargo.toml +8 -0
  45. package/crates/tish_core/src/json.rs +107 -56
  46. package/crates/tish_core/src/lib.rs +4 -2
  47. package/crates/tish_core/src/macros.rs +5 -5
  48. package/crates/tish_core/src/uri.rs +9 -6
  49. package/crates/tish_core/src/value.rs +145 -43
  50. package/crates/tish_core/src/vmref.rs +178 -0
  51. package/crates/tish_cranelift/src/link.rs +6 -9
  52. package/crates/tish_cranelift/src/lower.rs +14 -8
  53. package/crates/tish_eval/Cargo.toml +17 -2
  54. package/crates/tish_eval/src/eval.rs +474 -165
  55. package/crates/tish_eval/src/http.rs +61 -0
  56. package/crates/tish_eval/src/lib.rs +12 -8
  57. package/crates/tish_eval/src/natives.rs +136 -38
  58. package/crates/tish_eval/src/promise.rs +14 -8
  59. package/crates/tish_eval/src/timers.rs +28 -19
  60. package/crates/tish_eval/src/value.rs +17 -6
  61. package/crates/tish_eval/src/value_convert.rs +13 -5
  62. package/crates/tish_fmt/src/lib.rs +149 -43
  63. package/crates/tish_lexer/src/lib.rs +232 -63
  64. package/crates/tish_lexer/src/token.rs +10 -6
  65. package/crates/tish_llvm/src/lib.rs +17 -8
  66. package/crates/tish_lsp/Cargo.toml +4 -1
  67. package/crates/tish_lsp/README.md +1 -1
  68. package/crates/tish_lsp/src/builtin_goto.rs +261 -0
  69. package/crates/tish_lsp/src/import_goto.rs +549 -0
  70. package/crates/tish_lsp/src/main.rs +504 -106
  71. package/crates/tish_native/src/build.rs +4 -8
  72. package/crates/tish_native/src/lib.rs +54 -21
  73. package/crates/tish_opt/src/lib.rs +84 -52
  74. package/crates/tish_parser/src/lib.rs +45 -13
  75. package/crates/tish_parser/src/parser.rs +505 -130
  76. package/crates/tish_resolve/Cargo.toml +13 -0
  77. package/crates/tish_resolve/src/lib.rs +3436 -0
  78. package/crates/tish_resolve/src/pos.rs +133 -0
  79. package/crates/tish_runtime/Cargo.toml +68 -3
  80. package/crates/tish_runtime/src/http.rs +1136 -145
  81. package/crates/tish_runtime/src/http_fetch.rs +38 -27
  82. package/crates/tish_runtime/src/http_hyper.rs +418 -0
  83. package/crates/tish_runtime/src/http_prefork.rs +189 -0
  84. package/crates/tish_runtime/src/lib.rs +375 -189
  85. package/crates/tish_runtime/src/promise.rs +199 -40
  86. package/crates/tish_runtime/src/promise_io.rs +2 -1
  87. package/crates/tish_runtime/src/timers.rs +37 -1
  88. package/crates/tish_runtime/src/ws.rs +65 -42
  89. package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
  90. package/crates/tish_ui/src/jsx.rs +317 -27
  91. package/crates/tish_ui/src/lib.rs +5 -2
  92. package/crates/tish_ui/src/runtime/hooks.rs +406 -45
  93. package/crates/tish_ui/src/runtime/mod.rs +36 -9
  94. package/crates/tish_vm/Cargo.toml +15 -5
  95. package/crates/tish_vm/src/vm.rs +725 -281
  96. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +11 -4
  97. package/crates/tish_wasm/src/lib.rs +55 -42
  98. package/crates/tish_wasm_runtime/Cargo.toml +2 -1
  99. package/crates/tish_wasm_runtime/src/lib.rs +1 -1
  100. package/crates/tishlang_cargo_bindgen/Cargo.toml +26 -0
  101. package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
  102. package/crates/tishlang_cargo_bindgen/src/discover.rs +120 -0
  103. package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
  104. package/crates/tishlang_cargo_bindgen/src/lib.rs +350 -0
  105. package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
  106. package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -0
  107. package/justfile +8 -0
  108. package/package.json +1 -1
  109. package/platform/darwin-arm64/tish +0 -0
  110. package/platform/darwin-x64/tish +0 -0
  111. package/platform/linux-arm64/tish +0 -0
  112. package/platform/linux-x64/tish +0 -0
  113. package/platform/win32-x64/tish.exe +0 -0
@@ -52,7 +52,7 @@ macro_rules! binary_multi_op {
52
52
  }
53
53
 
54
54
  use tishlang_ast::{
55
- ArrowBody, ArrayElement, BinOp, CallArg, CompoundOp, DestructElement, DestructPattern,
55
+ ArrayElement, ArrowBody, BinOp, CallArg, CompoundOp, DestructElement, DestructPattern,
56
56
  DestructProp, ExportDeclaration, Expr, FunParam, ImportSpecifier, JsxAttrValue, JsxChild,
57
57
  JsxProp, Literal, LogicalAssignOp, MemberProp, ObjectProp, Program, Span, Statement,
58
58
  TypeAnnotation, TypedParam, UnaryOp,
@@ -86,19 +86,21 @@ impl<'a> Parser<'a> {
86
86
  }
87
87
 
88
88
  fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
89
- let t = self.advance().ok_or_else(|| format!("Expected {:?}, got EOF", kind))?;
89
+ let t = self
90
+ .advance()
91
+ .ok_or_else(|| format!("Expected {:?}, got EOF", kind))?;
90
92
  if t.kind == kind {
91
93
  Ok(t)
92
94
  } else {
93
- Err(format!("Expected {:?}, got {:?} at {:?}", kind, t.kind, t.span))
95
+ Err(format!(
96
+ "Expected {:?}, got {:?} at {:?}",
97
+ kind, t.kind, t.span
98
+ ))
94
99
  }
95
100
  }
96
101
 
97
102
  fn span_end(&self, start: (usize, usize)) -> Span {
98
- let end = self
99
- .peek()
100
- .map(|t| t.span.start)
101
- .unwrap_or(start);
103
+ let end = self.peek().map(|t| t.span.start).unwrap_or(start);
102
104
  Span { start, end }
103
105
  }
104
106
 
@@ -157,6 +159,8 @@ impl<'a> Parser<'a> {
157
159
  }
158
160
  TokenKind::Import => self.parse_import()?,
159
161
  TokenKind::Export => self.parse_export()?,
162
+ TokenKind::Type => self.parse_type_alias()?,
163
+ TokenKind::Declare => self.parse_declare()?,
160
164
  _ => {
161
165
  let expr = self.parse_expr()?;
162
166
  let span_end = expr.span().end;
@@ -207,18 +211,33 @@ impl<'a> Parser<'a> {
207
211
  statements.push(self.parse_statement()?);
208
212
  }
209
213
 
210
- if matches!(self.peek_kind(), Some(TokenKind::RBrace | TokenKind::Dedent)) {
214
+ if matches!(
215
+ self.peek_kind(),
216
+ Some(TokenKind::RBrace | TokenKind::Dedent)
217
+ ) {
211
218
  self.advance();
212
219
  }
213
220
 
221
+ let peek_end = self.peek().map(|x| x.span.end);
222
+ let last_end = statements.last().map(|s| s.span().end);
223
+ let end = match (peek_end, last_end) {
224
+ (Some(p), Some(l)) => {
225
+ if p.0 > l.0 || (p.0 == l.0 && p.1 > l.1) {
226
+ p
227
+ } else {
228
+ l
229
+ }
230
+ }
231
+ (Some(p), None) => p,
232
+ (None, Some(l)) => l,
233
+ (None, None) => span_start,
234
+ };
235
+
214
236
  Ok(Statement::Block {
215
237
  statements,
216
238
  span: Span {
217
239
  start: span_start,
218
- end: self
219
- .peek()
220
- .map(|x| x.span.end)
221
- .unwrap_or(span_start),
240
+ end,
222
241
  },
223
242
  })
224
243
  }
@@ -229,9 +248,12 @@ impl<'a> Parser<'a> {
229
248
  } else {
230
249
  self.expect(TokenKind::Const)?.span.start
231
250
  };
232
-
251
+
233
252
  // Check for destructuring pattern
234
- if matches!(self.peek_kind(), Some(TokenKind::LBracket) | Some(TokenKind::LBrace)) {
253
+ if matches!(
254
+ self.peek_kind(),
255
+ Some(TokenKind::LBracket) | Some(TokenKind::LBrace)
256
+ ) {
235
257
  let pattern = self.parse_destruct_pattern()?;
236
258
  self.expect(TokenKind::Assign)?;
237
259
  let init = self.parse_expr()?;
@@ -242,9 +264,13 @@ impl<'a> Parser<'a> {
242
264
  span: self.span_end(span_start),
243
265
  });
244
266
  }
245
-
246
- let name = self
247
- .expect(TokenKind::Ident)?
267
+
268
+ let name_tok = self.expect(TokenKind::Ident)?;
269
+ let name_span = Span {
270
+ start: name_tok.span.start,
271
+ end: name_tok.span.end,
272
+ };
273
+ let name = name_tok
248
274
  .literal
249
275
  .clone()
250
276
  .ok_or("Expected identifier")?;
@@ -265,13 +291,14 @@ impl<'a> Parser<'a> {
265
291
  };
266
292
  Ok(Statement::VarDecl {
267
293
  name,
294
+ name_span,
268
295
  mutable,
269
296
  type_ann,
270
297
  init,
271
298
  span: self.span_end(span_start),
272
299
  })
273
300
  }
274
-
301
+
275
302
  fn parse_destruct_pattern(&mut self) -> Result<DestructPattern, String> {
276
303
  match self.peek_kind() {
277
304
  Some(TokenKind::LBracket) => self.parse_array_destruct_pattern(),
@@ -279,11 +306,11 @@ impl<'a> Parser<'a> {
279
306
  _ => Err("Expected destructuring pattern".to_string()),
280
307
  }
281
308
  }
282
-
309
+
283
310
  fn parse_array_destruct_pattern(&mut self) -> Result<DestructPattern, String> {
284
311
  self.expect(TokenKind::LBracket)?;
285
312
  let mut elements = Vec::new();
286
-
313
+
287
314
  while !matches!(self.peek_kind(), Some(TokenKind::RBracket)) {
288
315
  // Handle holes (elision): [a, , b]
289
316
  if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
@@ -291,15 +318,23 @@ impl<'a> Parser<'a> {
291
318
  self.advance();
292
319
  continue;
293
320
  }
294
-
321
+
295
322
  // Rest element: ...rest
296
323
  if matches!(self.peek_kind(), Some(TokenKind::Spread)) {
297
324
  self.advance();
298
- let name = self.expect(TokenKind::Ident)?.literal.clone().ok_or("Expected identifier")?;
299
- elements.push(Some(DestructElement::Rest(name)));
325
+ let name_tok = self.expect(TokenKind::Ident)?;
326
+ let name_span = Span {
327
+ start: name_tok.span.start,
328
+ end: name_tok.span.end,
329
+ };
330
+ let name = name_tok
331
+ .literal
332
+ .clone()
333
+ .ok_or("Expected identifier")?;
334
+ elements.push(Some(DestructElement::Rest(name, name_span)));
300
335
  break;
301
336
  }
302
-
337
+
303
338
  // Nested pattern or identifier
304
339
  let elem = match self.peek_kind() {
305
340
  Some(TokenKind::LBracket) | Some(TokenKind::LBrace) => {
@@ -307,31 +342,47 @@ impl<'a> Parser<'a> {
307
342
  DestructElement::Pattern(Box::new(nested))
308
343
  }
309
344
  Some(TokenKind::Ident) => {
310
- let name = self.advance().ok_or("Unexpected EOF")?.literal.clone().ok_or("Expected identifier")?;
311
- DestructElement::Ident(name)
345
+ let name_tok = self.advance().ok_or("Unexpected EOF")?;
346
+ let name_span = Span {
347
+ start: name_tok.span.start,
348
+ end: name_tok.span.end,
349
+ };
350
+ let name = name_tok
351
+ .literal
352
+ .clone()
353
+ .ok_or("Expected identifier")?;
354
+ DestructElement::Ident(name, name_span)
312
355
  }
313
356
  _ => return Err("Expected identifier or pattern in destructuring".to_string()),
314
357
  };
315
358
  elements.push(Some(elem));
316
-
359
+
317
360
  if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
318
361
  self.advance();
319
362
  } else {
320
363
  break;
321
364
  }
322
365
  }
323
-
366
+
324
367
  self.expect(TokenKind::RBracket)?;
325
368
  Ok(DestructPattern::Array(elements))
326
369
  }
327
-
370
+
328
371
  fn parse_object_destruct_pattern(&mut self) -> Result<DestructPattern, String> {
329
372
  self.expect(TokenKind::LBrace)?;
330
373
  let mut props = Vec::new();
331
-
374
+
332
375
  while !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
333
- let key = self.expect(TokenKind::Ident)?.literal.clone().ok_or("Expected identifier")?;
334
-
376
+ let key_tok = self.expect(TokenKind::Ident)?;
377
+ let key_span = Span {
378
+ start: key_tok.span.start,
379
+ end: key_tok.span.end,
380
+ };
381
+ let key = key_tok
382
+ .literal
383
+ .clone()
384
+ .ok_or("Expected identifier")?;
385
+
335
386
  let value = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
336
387
  self.advance();
337
388
  // Could be renamed binding or nested pattern
@@ -341,25 +392,33 @@ impl<'a> Parser<'a> {
341
392
  DestructElement::Pattern(Box::new(nested))
342
393
  }
343
394
  Some(TokenKind::Ident) => {
344
- let name = self.advance().ok_or("Unexpected EOF")?.literal.clone().ok_or("Expected identifier")?;
345
- DestructElement::Ident(name)
395
+ let name_tok = self.advance().ok_or("Unexpected EOF")?;
396
+ let name_span = Span {
397
+ start: name_tok.span.start,
398
+ end: name_tok.span.end,
399
+ };
400
+ let name = name_tok
401
+ .literal
402
+ .clone()
403
+ .ok_or("Expected identifier")?;
404
+ DestructElement::Ident(name, name_span)
346
405
  }
347
406
  _ => return Err("Expected identifier or pattern after ':'".to_string()),
348
407
  }
349
408
  } else {
350
409
  // Shorthand: { key } is equivalent to { key: key }
351
- DestructElement::Ident(key.clone())
410
+ DestructElement::Ident(key.clone(), key_span)
352
411
  };
353
-
412
+
354
413
  props.push(DestructProp { key, value });
355
-
414
+
356
415
  if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
357
416
  self.advance();
358
417
  } else {
359
418
  break;
360
419
  }
361
420
  }
362
-
421
+
363
422
  self.expect(TokenKind::RBrace)?;
364
423
  Ok(DestructPattern::Object(props))
365
424
  }
@@ -389,8 +448,12 @@ impl<'a> Parser<'a> {
389
448
  default,
390
449
  });
391
450
  }
392
- let param_name = self
393
- .expect(TokenKind::Ident)?
451
+ let param_tok = self.expect(TokenKind::Ident)?;
452
+ let name_span = Span {
453
+ start: param_tok.span.start,
454
+ end: param_tok.span.end,
455
+ };
456
+ let param_name = param_tok
394
457
  .literal
395
458
  .clone()
396
459
  .ok_or("Expected param name")?;
@@ -408,22 +471,23 @@ impl<'a> Parser<'a> {
408
471
  };
409
472
  Ok(FunParam::Simple(TypedParam {
410
473
  name: param_name,
474
+ name_span,
411
475
  type_ann,
412
476
  default,
413
477
  }))
414
478
  }
415
-
479
+
416
480
  /// Parse a type annotation (number, string, T[], {a: T}, etc.)
417
481
  fn parse_type_annotation(&mut self) -> Result<TypeAnnotation, String> {
418
482
  let base = self.parse_type_primary()?;
419
-
483
+
420
484
  // Check for array suffix: T[]
421
485
  if matches!(self.peek_kind(), Some(TokenKind::LBracket)) {
422
486
  self.advance(); // [
423
487
  self.expect(TokenKind::RBracket)?; // ]
424
488
  return Ok(TypeAnnotation::Array(Box::new(base)));
425
489
  }
426
-
490
+
427
491
  // Check for union: T | U
428
492
  if matches!(self.peek_kind(), Some(TokenKind::BitOr)) {
429
493
  let mut types = vec![base];
@@ -433,10 +497,10 @@ impl<'a> Parser<'a> {
433
497
  }
434
498
  return Ok(TypeAnnotation::Union(types));
435
499
  }
436
-
500
+
437
501
  Ok(base)
438
502
  }
439
-
503
+
440
504
  /// Parse a primary type (identifier, object, or function type)
441
505
  fn parse_type_primary(&mut self) -> Result<TypeAnnotation, String> {
442
506
  match self.peek_kind() {
@@ -445,6 +509,11 @@ impl<'a> Parser<'a> {
445
509
  let name = tok.literal.clone().ok_or("Expected type name")?;
446
510
  Ok(TypeAnnotation::Simple(name))
447
511
  }
512
+ Some(TokenKind::Type | TokenKind::Declare) => {
513
+ let tok = self.advance().ok_or("Expected type name")?;
514
+ let name = tok.literal.clone().ok_or("Expected type name")?;
515
+ Ok(TypeAnnotation::Simple(name))
516
+ }
448
517
  // Handle keywords that can be type names
449
518
  Some(TokenKind::Null) => {
450
519
  self.advance();
@@ -459,14 +528,22 @@ impl<'a> Parser<'a> {
459
528
  self.advance(); // {
460
529
  let mut props = Vec::new();
461
530
  while !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
462
- let key = self.expect(TokenKind::Ident)?.literal.clone()
531
+ let key = self
532
+ .expect(TokenKind::Ident)?
533
+ .literal
534
+ .clone()
463
535
  .ok_or("Expected property name")?;
464
536
  self.expect(TokenKind::Colon)?;
465
537
  let typ = self.parse_type_annotation()?;
466
538
  props.push((key, typ));
467
539
  if !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
468
- // Allow trailing comma or require comma between items
469
- if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
540
+ // Accept `,` or `;` between items (TypeScript-style
541
+ // semicolons are common in interface/object type
542
+ // declarations); also tolerate a trailing separator.
543
+ if matches!(
544
+ self.peek_kind(),
545
+ Some(TokenKind::Comma) | Some(TokenKind::Semicolon)
546
+ ) {
470
547
  self.advance();
471
548
  }
472
549
  }
@@ -485,9 +562,7 @@ impl<'a> Parser<'a> {
485
562
  }
486
563
  }
487
564
  self.expect(TokenKind::RParen)?;
488
- // Expect => for return type
489
- self.expect(TokenKind::Assign)?; // =
490
- self.expect(TokenKind::Gt)?; // > (forms =>)
565
+ self.expect(TokenKind::Arrow)?;
491
566
  let returns = self.parse_type_annotation()?;
492
567
  Ok(TypeAnnotation::Function {
493
568
  params,
@@ -500,8 +575,12 @@ impl<'a> Parser<'a> {
500
575
 
501
576
  fn parse_fun_decl(&mut self, async_: bool) -> Result<Statement, String> {
502
577
  let span_start = self.expect(TokenKind::Fn)?.span.start;
503
- let name = self
504
- .expect(TokenKind::Ident)?
578
+ let name_tok = self.expect(TokenKind::Ident)?;
579
+ let name_span = Span {
580
+ start: name_tok.span.start,
581
+ end: name_tok.span.end,
582
+ };
583
+ let name = name_tok
505
584
  .literal
506
585
  .clone()
507
586
  .ok_or("Expected function name")?;
@@ -511,8 +590,12 @@ impl<'a> Parser<'a> {
511
590
  while !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
512
591
  if matches!(self.peek_kind(), Some(TokenKind::Spread)) {
513
592
  self.advance();
514
- let param_name = self
515
- .expect(TokenKind::Ident)?
593
+ let rest_tok = self.expect(TokenKind::Ident)?;
594
+ let rest_name_span = Span {
595
+ start: rest_tok.span.start,
596
+ end: rest_tok.span.end,
597
+ };
598
+ let param_name = rest_tok
516
599
  .literal
517
600
  .clone()
518
601
  .ok_or("Expected rest param name")?;
@@ -523,7 +606,12 @@ impl<'a> Parser<'a> {
523
606
  } else {
524
607
  None
525
608
  };
526
- rest_param = Some(TypedParam { name: param_name, type_ann, default: None });
609
+ rest_param = Some(TypedParam {
610
+ name: param_name,
611
+ name_span: rest_name_span,
612
+ type_ann,
613
+ default: None,
614
+ });
527
615
  if !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
528
616
  return Err("Rest parameter must be last".to_string());
529
617
  }
@@ -535,7 +623,7 @@ impl<'a> Parser<'a> {
535
623
  }
536
624
  }
537
625
  self.expect(TokenKind::RParen)?;
538
-
626
+
539
627
  // Optional return type: `: Type`
540
628
  let return_type = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
541
629
  self.advance();
@@ -559,13 +647,182 @@ impl<'a> Parser<'a> {
559
647
  Box::new(self.parse_block()?)
560
648
  };
561
649
 
650
+ // Span must cover the whole declaration through the body. `peek().start` alone can sit on
651
+ // the opening `{` (same as `span_start` at EOF) or otherwise truncate before inner spans.
652
+ let peek_start = self.peek().map(|t| t.span.start).unwrap_or(span_start);
653
+ let body_end = body.as_ref().span().end;
654
+ let end = if peek_start.0 > body_end.0
655
+ || (peek_start.0 == body_end.0 && peek_start.1 > body_end.1)
656
+ {
657
+ peek_start
658
+ } else {
659
+ body_end
660
+ };
661
+
562
662
  Ok(Statement::FunDecl {
563
663
  async_,
564
664
  name,
665
+ name_span,
565
666
  params,
566
667
  rest_param,
567
668
  return_type,
568
669
  body,
670
+ span: Span {
671
+ start: span_start,
672
+ end,
673
+ },
674
+ })
675
+ }
676
+
677
+ fn parse_type_alias(&mut self) -> Result<Statement, String> {
678
+ let span_start = self.expect(TokenKind::Type)?.span.start;
679
+ let name_tok = self.expect(TokenKind::Ident)?;
680
+ let name_span = Span {
681
+ start: name_tok.span.start,
682
+ end: name_tok.span.end,
683
+ };
684
+ let name = name_tok
685
+ .literal
686
+ .clone()
687
+ .ok_or("Expected type alias name")?;
688
+ self.expect(TokenKind::Assign)?;
689
+ let ty = self.parse_type_annotation()?;
690
+ Ok(Statement::TypeAlias {
691
+ name,
692
+ name_span,
693
+ ty,
694
+ span: self.span_end(span_start),
695
+ })
696
+ }
697
+
698
+ fn parse_declare(&mut self) -> Result<Statement, String> {
699
+ let span_start = self.expect(TokenKind::Declare)?.span.start;
700
+ let async_ = if matches!(self.peek_kind(), Some(TokenKind::Async)) {
701
+ self.advance();
702
+ true
703
+ } else {
704
+ false
705
+ };
706
+ if matches!(self.peek_kind(), Some(TokenKind::Fn)) {
707
+ return self.parse_declare_fun(span_start, async_);
708
+ }
709
+ let const_ = match self.peek_kind() {
710
+ Some(TokenKind::Let) => {
711
+ self.advance();
712
+ false
713
+ }
714
+ Some(TokenKind::Const) => {
715
+ self.advance();
716
+ true
717
+ }
718
+ _ => {
719
+ return Err(
720
+ "Expected `let`, `const`, `async fn`, or `fn` after `declare`".to_string(),
721
+ );
722
+ }
723
+ };
724
+ let name_tok = self.expect(TokenKind::Ident)?;
725
+ let name_span = Span {
726
+ start: name_tok.span.start,
727
+ end: name_tok.span.end,
728
+ };
729
+ let name = name_tok
730
+ .literal
731
+ .clone()
732
+ .ok_or("Expected identifier")?;
733
+ let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
734
+ self.advance();
735
+ Some(self.parse_type_annotation()?)
736
+ } else {
737
+ None
738
+ };
739
+ if matches!(self.peek_kind(), Some(TokenKind::Assign)) {
740
+ return Err("`declare` cannot have an initializer".to_string());
741
+ }
742
+ Ok(Statement::DeclareVar {
743
+ name,
744
+ name_span,
745
+ type_ann,
746
+ const_,
747
+ span: self.span_end(span_start),
748
+ })
749
+ }
750
+
751
+ fn parse_declare_fun(
752
+ &mut self,
753
+ span_start: (usize, usize),
754
+ async_: bool,
755
+ ) -> Result<Statement, String> {
756
+ self.expect(TokenKind::Fn)?;
757
+ let name_tok = self.expect(TokenKind::Ident)?;
758
+ let name_span = Span {
759
+ start: name_tok.span.start,
760
+ end: name_tok.span.end,
761
+ };
762
+ let name = name_tok
763
+ .literal
764
+ .clone()
765
+ .ok_or("Expected function name")?;
766
+ self.expect(TokenKind::LParen)?;
767
+ let mut params = Vec::with_capacity(4);
768
+ let mut rest_param = None;
769
+ while !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
770
+ if matches!(self.peek_kind(), Some(TokenKind::Spread)) {
771
+ self.advance();
772
+ let rest_tok = self.expect(TokenKind::Ident)?;
773
+ let rest_name_span = Span {
774
+ start: rest_tok.span.start,
775
+ end: rest_tok.span.end,
776
+ };
777
+ let param_name = rest_tok
778
+ .literal
779
+ .clone()
780
+ .ok_or("Expected rest param name")?;
781
+ let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
782
+ self.advance();
783
+ Some(self.parse_type_annotation()?)
784
+ } else {
785
+ None
786
+ };
787
+ rest_param = Some(TypedParam {
788
+ name: param_name,
789
+ name_span: rest_name_span,
790
+ type_ann,
791
+ default: None,
792
+ });
793
+ if !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
794
+ return Err("Rest parameter must be last".to_string());
795
+ }
796
+ break;
797
+ }
798
+ params.push(self.parse_fun_param()?);
799
+ if !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
800
+ self.expect(TokenKind::Comma)?;
801
+ }
802
+ }
803
+ self.expect(TokenKind::RParen)?;
804
+ let return_type = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
805
+ self.advance();
806
+ Some(self.parse_type_annotation()?)
807
+ } else {
808
+ None
809
+ };
810
+ if matches!(
811
+ self.peek_kind(),
812
+ Some(TokenKind::Assign | TokenKind::LBrace | TokenKind::Indent)
813
+ ) {
814
+ return Err("`declare function` must not have a body".to_string());
815
+ }
816
+ if matches!(self.peek_kind(), Some(TokenKind::Semicolon)) {
817
+ self.advance();
818
+ }
819
+ Ok(Statement::DeclareFun {
820
+ async_,
821
+ name,
822
+ name_span,
823
+ params,
824
+ rest_param,
825
+ return_type,
569
826
  span: self.span_end(span_start),
570
827
  })
571
828
  }
@@ -610,8 +867,12 @@ impl<'a> Parser<'a> {
610
867
  let mutable = matches!(self.peek_kind(), Some(TokenKind::Let));
611
868
  let var_span_start = self.peek().map(|t| t.span.start).unwrap_or((0, 0));
612
869
  self.advance();
613
- let name = self
614
- .expect(TokenKind::Ident)?
870
+ let for_name_tok = self.expect(TokenKind::Ident)?;
871
+ let name_span = Span {
872
+ start: for_name_tok.span.start,
873
+ end: for_name_tok.span.end,
874
+ };
875
+ let name = for_name_tok
615
876
  .literal
616
877
  .clone()
617
878
  .ok_or("Expected identifier")?;
@@ -622,6 +883,7 @@ impl<'a> Parser<'a> {
622
883
  let body = Box::new(self.parse_block_or_statement()?);
623
884
  return Ok(Statement::ForOf {
624
885
  name,
886
+ name_span,
625
887
  iterable,
626
888
  body,
627
889
  span: self.span_end(span_start),
@@ -644,6 +906,7 @@ impl<'a> Parser<'a> {
644
906
  }
645
907
  Some(Box::new(Statement::VarDecl {
646
908
  name,
909
+ name_span,
647
910
  mutable,
648
911
  type_ann,
649
912
  init: init_expr,
@@ -665,7 +928,10 @@ impl<'a> Parser<'a> {
665
928
  if matches!(self.peek_kind(), Some(TokenKind::Semicolon)) {
666
929
  self.advance();
667
930
  }
668
- let cond = if matches!(self.peek_kind(), Some(TokenKind::Semicolon | TokenKind::RParen)) {
931
+ let cond = if matches!(
932
+ self.peek_kind(),
933
+ Some(TokenKind::Semicolon | TokenKind::RParen)
934
+ ) {
669
935
  None
670
936
  } else {
671
937
  let c = self.parse_expr()?;
@@ -780,31 +1046,38 @@ impl<'a> Parser<'a> {
780
1046
  fn parse_try(&mut self) -> Result<Statement, String> {
781
1047
  let span_start = self.expect(TokenKind::Try)?.span.start;
782
1048
  let body = Box::new(self.parse_block_or_statement()?);
783
-
1049
+
784
1050
  let mut catch_param = None;
1051
+ let mut catch_param_span = None;
785
1052
  let mut catch_body = None;
786
1053
  let mut finally_body = None;
787
-
1054
+
788
1055
  if matches!(self.peek_kind(), Some(TokenKind::Catch)) {
789
1056
  self.advance();
790
1057
  self.expect(TokenKind::LParen)?;
791
- catch_param = self.expect(TokenKind::Ident)?.literal.clone();
1058
+ let catch_tok = self.expect(TokenKind::Ident)?;
1059
+ catch_param_span = Some(Span {
1060
+ start: catch_tok.span.start,
1061
+ end: catch_tok.span.end,
1062
+ });
1063
+ catch_param = catch_tok.literal.clone();
792
1064
  self.expect(TokenKind::RParen)?;
793
1065
  catch_body = Some(Box::new(self.parse_block_or_statement()?));
794
1066
  }
795
-
1067
+
796
1068
  if matches!(self.peek_kind(), Some(TokenKind::Finally)) {
797
1069
  self.advance();
798
1070
  finally_body = Some(Box::new(self.parse_block_or_statement()?));
799
1071
  }
800
-
1072
+
801
1073
  if catch_body.is_none() && finally_body.is_none() {
802
1074
  return Err("try statement requires catch or finally".to_string());
803
1075
  }
804
-
1076
+
805
1077
  Ok(Statement::Try {
806
1078
  body,
807
1079
  catch_param,
1080
+ catch_param_span,
808
1081
  catch_body,
809
1082
  finally_body,
810
1083
  span: self.span_end(span_start),
@@ -818,25 +1091,42 @@ impl<'a> Parser<'a> {
818
1091
  self.advance();
819
1092
  let mut specs = Vec::new();
820
1093
  while !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
821
- let name = self
822
- .expect(TokenKind::Ident)?
1094
+ let name_tok = self.expect(TokenKind::Ident)?;
1095
+ let name_span = Span {
1096
+ start: name_tok.span.start,
1097
+ end: name_tok.span.end,
1098
+ };
1099
+ let name = name_tok
823
1100
  .literal
824
1101
  .clone()
825
1102
  .ok_or("Expected identifier in import")?;
826
- let alias = if matches!(self.peek_kind(), Some(TokenKind::Ident))
1103
+ let (alias, alias_span) = if matches!(self.peek_kind(), Some(TokenKind::Ident))
827
1104
  && self.peek().and_then(|t| t.literal.as_deref()) == Some("as")
828
1105
  {
829
1106
  self.advance(); // consume 'as'
830
- Some(
831
- self.expect(TokenKind::Ident)?
832
- .literal
833
- .clone()
834
- .ok_or("Expected alias after 'as'")?,
1107
+ let alias_tok = self.expect(TokenKind::Ident)?;
1108
+ let asp = Span {
1109
+ start: alias_tok.span.start,
1110
+ end: alias_tok.span.end,
1111
+ };
1112
+ (
1113
+ Some(
1114
+ alias_tok
1115
+ .literal
1116
+ .clone()
1117
+ .ok_or("Expected alias after 'as'")?,
1118
+ ),
1119
+ Some(asp),
835
1120
  )
836
1121
  } else {
837
- None
1122
+ (None, None)
838
1123
  };
839
- specs.push(ImportSpecifier::Named { name, alias });
1124
+ specs.push(ImportSpecifier::Named {
1125
+ name,
1126
+ name_span,
1127
+ alias,
1128
+ alias_span,
1129
+ });
840
1130
  if !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
841
1131
  self.expect(TokenKind::Comma)?;
842
1132
  }
@@ -850,20 +1140,31 @@ impl<'a> Parser<'a> {
850
1140
  if as_tok.literal.as_deref() != Some("as") {
851
1141
  return Err("Expected 'as' after '*' in namespace import".to_string());
852
1142
  }
853
- let alias = self
854
- .expect(TokenKind::Ident)?
1143
+ let alias_tok = self.expect(TokenKind::Ident)?;
1144
+ let name_span = Span {
1145
+ start: alias_tok.span.start,
1146
+ end: alias_tok.span.end,
1147
+ };
1148
+ let alias = alias_tok
855
1149
  .literal
856
1150
  .clone()
857
1151
  .ok_or("Expected identifier after 'as'")?;
858
- vec![ImportSpecifier::Namespace(alias)]
1152
+ vec![ImportSpecifier::Namespace {
1153
+ name: alias,
1154
+ name_span,
1155
+ }]
859
1156
  } else if matches!(self.peek_kind(), Some(TokenKind::Ident)) {
860
1157
  // Default: import X from "..."
861
- let name = self
862
- .expect(TokenKind::Ident)?
1158
+ let def_tok = self.expect(TokenKind::Ident)?;
1159
+ let name_span = Span {
1160
+ start: def_tok.span.start,
1161
+ end: def_tok.span.end,
1162
+ };
1163
+ let name = def_tok
863
1164
  .literal
864
1165
  .clone()
865
1166
  .ok_or("Expected identifier")?;
866
- vec![ImportSpecifier::Default(name)]
1167
+ vec![ImportSpecifier::Default { name, name_span }]
867
1168
  } else {
868
1169
  return Err("Expected { }, * as name, or default import".to_string());
869
1170
  };
@@ -889,6 +1190,10 @@ impl<'a> Parser<'a> {
889
1190
  self.advance();
890
1191
  let expr = self.parse_expr()?;
891
1192
  ExportDeclaration::Default(expr)
1193
+ } else if matches!(self.peek_kind(), Some(TokenKind::Type)) {
1194
+ ExportDeclaration::Named(Box::new(self.parse_type_alias()?))
1195
+ } else if matches!(self.peek_kind(), Some(TokenKind::Declare)) {
1196
+ ExportDeclaration::Named(Box::new(self.parse_declare()?))
892
1197
  } else if matches!(self.peek_kind(), Some(TokenKind::Const)) {
893
1198
  ExportDeclaration::Named(Box::new(self.parse_var_decl(false)?))
894
1199
  } else if matches!(self.peek_kind(), Some(TokenKind::Let)) {
@@ -902,7 +1207,10 @@ impl<'a> Parser<'a> {
902
1207
  }
903
1208
  ExportDeclaration::Named(Box::new(self.parse_fun_decl(async_)?))
904
1209
  } else {
905
- return Err("Expected 'default', 'const', 'let', or 'fn' after export".to_string());
1210
+ return Err(
1211
+ "Expected 'default', 'type', 'declare', 'const', 'let', or 'fn' after export"
1212
+ .to_string(),
1213
+ );
906
1214
  };
907
1215
  Ok(Statement::Export {
908
1216
  declaration: Box::new(declaration),
@@ -920,7 +1228,7 @@ impl<'a> Parser<'a> {
920
1228
  // Check for simple assignment
921
1229
  if matches!(self.peek_kind(), Some(TokenKind::Assign)) {
922
1230
  let start = left.span().start;
923
-
1231
+
924
1232
  // Variable assignment: x = val
925
1233
  if let Expr::Ident { name, .. } = &left {
926
1234
  let name = Arc::clone(name);
@@ -933,9 +1241,14 @@ impl<'a> Parser<'a> {
933
1241
  span: Span { start, end },
934
1242
  });
935
1243
  }
936
-
1244
+
937
1245
  // Member assignment: obj.prop = val
938
- if let Expr::Member { object, prop: MemberProp::Name(prop_name), .. } = &left {
1246
+ if let Expr::Member {
1247
+ object,
1248
+ prop: MemberProp::Name { name: prop_name, .. },
1249
+ ..
1250
+ } = &left
1251
+ {
939
1252
  let object = Box::clone(object);
940
1253
  let prop = Arc::clone(prop_name);
941
1254
  self.advance(); // =
@@ -948,7 +1261,7 @@ impl<'a> Parser<'a> {
948
1261
  span: Span { start, end },
949
1262
  });
950
1263
  }
951
-
1264
+
952
1265
  // Index assignment: arr[idx] = val or obj[key] = val
953
1266
  if let Expr::Index { object, index, .. } = &left {
954
1267
  let object = Box::clone(object);
@@ -1060,7 +1373,7 @@ impl<'a> Parser<'a> {
1060
1373
  binary_single_op!(parse_bit_or, parse_bit_xor, BitOr, BinOp::BitOr);
1061
1374
  binary_single_op!(parse_bit_xor, parse_bit_and, BitXor, BinOp::BitXor);
1062
1375
  binary_single_op!(parse_bit_and, parse_shift, BitAnd, BinOp::BitAnd);
1063
-
1376
+
1064
1377
  binary_multi_op!(parse_shift, parse_equality, Shl => BinOp::Shl, Shr => BinOp::Shr);
1065
1378
  binary_multi_op!(parse_equality, parse_comparison,
1066
1379
  StrictEq => BinOp::StrictEq, StrictNe => BinOp::StrictNe,
@@ -1099,14 +1412,20 @@ impl<'a> Parser<'a> {
1099
1412
  let operand = self.parse_unary()?;
1100
1413
  if let Expr::Ident { name, span } = &operand {
1101
1414
  let name = Arc::clone(name);
1102
- let span = Span { start: span_start, end: span.end };
1415
+ let span = Span {
1416
+ start: span_start,
1417
+ end: span.end,
1418
+ };
1103
1419
  return Ok(if is_inc {
1104
1420
  Expr::PrefixInc { name, span }
1105
1421
  } else {
1106
1422
  Expr::PrefixDec { name, span }
1107
1423
  });
1108
1424
  }
1109
- return Err(format!("Prefix {} requires an identifier", if is_inc { "++" } else { "--" }));
1425
+ return Err(format!(
1426
+ "Prefix {} requires an identifier",
1427
+ if is_inc { "++" } else { "--" }
1428
+ ));
1110
1429
  }
1111
1430
  let op = match self.peek_kind() {
1112
1431
  Some(TokenKind::Not) => UnaryOp::Not,
@@ -1134,7 +1453,10 @@ impl<'a> Parser<'a> {
1134
1453
  let end = operand.span().end;
1135
1454
  return Ok(Expr::Await {
1136
1455
  operand: Box::new(operand),
1137
- span: Span { start: span_start, end },
1456
+ span: Span {
1457
+ start: span_start,
1458
+ end,
1459
+ },
1138
1460
  });
1139
1461
  }
1140
1462
  _ => return self.parse_postfix(),
@@ -1161,16 +1483,23 @@ impl<'a> Parser<'a> {
1161
1483
  TokenKind::Dot | TokenKind::OptionalChain => {
1162
1484
  let optional = kind == TokenKind::OptionalChain;
1163
1485
  self.advance();
1164
- let prop = self
1165
- .expect(TokenKind::Ident)?
1486
+ let prop_tok = self.expect(TokenKind::Ident)?;
1487
+ let prop = prop_tok
1166
1488
  .literal
1167
1489
  .clone()
1168
1490
  .ok_or("Expected property name")?;
1491
+ let prop_span = Span {
1492
+ start: prop_tok.span.start,
1493
+ end: prop_tok.span.end,
1494
+ };
1169
1495
  let start = expr.span().start;
1170
1496
  let end = self.peek().map(|x| x.span.start).unwrap_or(start);
1171
1497
  expr = Expr::Member {
1172
1498
  object: Box::new(expr),
1173
- prop: MemberProp::Name(prop),
1499
+ prop: MemberProp::Name {
1500
+ name: prop,
1501
+ span: prop_span,
1502
+ },
1174
1503
  optional,
1175
1504
  span: Span { start, end },
1176
1505
  };
@@ -1274,16 +1603,23 @@ impl<'a> Parser<'a> {
1274
1603
  TokenKind::Dot | TokenKind::OptionalChain => {
1275
1604
  let optional = kind == TokenKind::OptionalChain;
1276
1605
  self.advance();
1277
- let prop = self
1278
- .expect(TokenKind::Ident)?
1606
+ let prop_tok = self.expect(TokenKind::Ident)?;
1607
+ let prop = prop_tok
1279
1608
  .literal
1280
1609
  .clone()
1281
1610
  .ok_or("Expected property name")?;
1611
+ let prop_span = Span {
1612
+ start: prop_tok.span.start,
1613
+ end: prop_tok.span.end,
1614
+ };
1282
1615
  let start = expr.span().start;
1283
1616
  let end = self.peek().map(|x| x.span.start).unwrap_or(start);
1284
1617
  expr = Expr::Member {
1285
1618
  object: Box::new(expr),
1286
- prop: MemberProp::Name(prop),
1619
+ prop: MemberProp::Name {
1620
+ name: prop,
1621
+ span: prop_span,
1622
+ },
1287
1623
  optional,
1288
1624
  span: Span { start, end },
1289
1625
  };
@@ -1302,11 +1638,18 @@ impl<'a> Parser<'a> {
1302
1638
  };
1303
1639
  }
1304
1640
  TokenKind::PlusPlus | TokenKind::MinusMinus => {
1305
- if let Expr::Ident { name, span: ident_span } = &expr {
1641
+ if let Expr::Ident {
1642
+ name,
1643
+ span: ident_span,
1644
+ } = &expr
1645
+ {
1306
1646
  let name = Arc::clone(name);
1307
1647
  let is_inc = kind == TokenKind::PlusPlus;
1308
1648
  let tok = self.advance().ok_or("Unexpected EOF")?;
1309
- let span = Span { start: ident_span.start, end: tok.span.end };
1649
+ let span = Span {
1650
+ start: ident_span.start,
1651
+ end: tok.span.end,
1652
+ };
1310
1653
  expr = if is_inc {
1311
1654
  Expr::PostfixInc { name, span }
1312
1655
  } else {
@@ -1370,11 +1713,15 @@ impl<'a> Parser<'a> {
1370
1713
  return Ok(Expr::ArrowFunction {
1371
1714
  params: vec![FunParam::Simple(TypedParam {
1372
1715
  name: name.clone(),
1716
+ name_span: span,
1373
1717
  type_ann: None,
1374
1718
  default: None,
1375
1719
  })],
1376
1720
  body,
1377
- span: Span { start: span.start, end },
1721
+ span: Span {
1722
+ start: span.start,
1723
+ end,
1724
+ },
1378
1725
  });
1379
1726
  }
1380
1727
  Ok(Expr::Ident { name, span })
@@ -1418,7 +1765,10 @@ impl<'a> Parser<'a> {
1418
1765
  match self.peek_kind() {
1419
1766
  Some(TokenKind::Ident) => self.parse_jsx_element(span.start),
1420
1767
  Some(TokenKind::Gt) => self.parse_jsx_fragment(span.start),
1421
- _ => Err(format!("Invalid JSX: expected tag name or <> after <, got {:?}", self.peek_kind())),
1768
+ _ => Err(format!(
1769
+ "Invalid JSX: expected tag name or <> after <, got {:?}",
1770
+ self.peek_kind()
1771
+ )),
1422
1772
  }
1423
1773
  }
1424
1774
  TokenKind::LBrace => {
@@ -1431,11 +1781,8 @@ impl<'a> Parser<'a> {
1431
1781
  } else {
1432
1782
  let key_tok = self.advance().ok_or("Expected object key")?;
1433
1783
  let (key, key_span, is_ident_key) = match key_tok.kind {
1434
- TokenKind::Ident => {
1435
- let k = key_tok
1436
- .literal
1437
- .clone()
1438
- .ok_or("Expected key")?;
1784
+ TokenKind::Ident | TokenKind::Type | TokenKind::Declare => {
1785
+ let k = key_tok.literal.clone().ok_or("Expected key")?;
1439
1786
  let sp = Span {
1440
1787
  start: key_tok.span.start,
1441
1788
  end: key_tok.span.end,
@@ -1443,20 +1790,19 @@ impl<'a> Parser<'a> {
1443
1790
  (k, sp, true)
1444
1791
  }
1445
1792
  TokenKind::String => {
1446
- let k = key_tok
1447
- .literal
1448
- .clone()
1449
- .ok_or("Expected string key")?;
1793
+ let k = key_tok.literal.clone().ok_or("Expected string key")?;
1450
1794
  let sp = Span {
1451
1795
  start: key_tok.span.start,
1452
1796
  end: key_tok.span.end,
1453
1797
  };
1454
1798
  (k, sp, false)
1455
1799
  }
1456
- _ => return Err(format!(
1457
- "Expected object key (ident or string), got {:?}",
1458
- key_tok.kind
1459
- )),
1800
+ _ => {
1801
+ return Err(format!(
1802
+ "Expected object key (ident or string), got {:?}",
1803
+ key_tok.kind
1804
+ ))
1805
+ }
1460
1806
  };
1461
1807
  let value = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
1462
1808
  self.expect(TokenKind::Colon)?;
@@ -1499,12 +1845,12 @@ impl<'a> Parser<'a> {
1499
1845
  // Template literal with interpolation: `text${
1500
1846
  let mut quasis = vec![t.literal.clone().unwrap_or_default()];
1501
1847
  let mut exprs = Vec::new();
1502
-
1848
+
1503
1849
  loop {
1504
1850
  // Parse the expression inside ${}
1505
1851
  let expr = self.parse_expr()?;
1506
1852
  exprs.push(expr);
1507
-
1853
+
1508
1854
  // Next token should be TemplateMiddle or TemplateTail
1509
1855
  let next = self.advance().ok_or("Unexpected EOF in template literal")?;
1510
1856
  match next.kind {
@@ -1514,14 +1860,22 @@ impl<'a> Parser<'a> {
1514
1860
  return Ok(Expr::TemplateLiteral {
1515
1861
  quasis,
1516
1862
  exprs,
1517
- span: Span { start: span.start, end },
1863
+ span: Span {
1864
+ start: span.start,
1865
+ end,
1866
+ },
1518
1867
  });
1519
1868
  }
1520
1869
  TokenKind::TemplateMiddle => {
1521
1870
  quasis.push(next.literal.clone().unwrap_or_default());
1522
1871
  // Continue parsing more expressions
1523
1872
  }
1524
- _ => return Err(format!("Expected template continuation, got {:?}", next.kind)),
1873
+ _ => {
1874
+ return Err(format!(
1875
+ "Expected template continuation, got {:?}",
1876
+ next.kind
1877
+ ))
1878
+ }
1525
1879
  }
1526
1880
  }
1527
1881
  }
@@ -1534,11 +1888,11 @@ impl<'a> Parser<'a> {
1534
1888
  fn try_parse_arrow_function(&mut self, start_span: &Span) -> Result<Option<Expr>, String> {
1535
1889
  // Save position for backtracking
1536
1890
  let saved_pos = self.pos;
1537
-
1891
+
1538
1892
  // Try to parse as arrow function params
1539
1893
  let mut params = Vec::new();
1540
1894
  let mut is_arrow = false;
1541
-
1895
+
1542
1896
  // Check for empty params: () => ...
1543
1897
  if matches!(self.peek_kind(), Some(TokenKind::RParen)) {
1544
1898
  self.advance(); // consume )
@@ -1574,20 +1928,23 @@ impl<'a> Parser<'a> {
1574
1928
  }
1575
1929
  }
1576
1930
  }
1577
-
1931
+
1578
1932
  if !is_arrow {
1579
1933
  // Backtrack - it's not an arrow function
1580
1934
  self.pos = saved_pos;
1581
1935
  return Ok(None);
1582
1936
  }
1583
-
1937
+
1584
1938
  let body = self.parse_arrow_body()?;
1585
1939
  let end = self.previous_span_end();
1586
-
1940
+
1587
1941
  Ok(Some(Expr::ArrowFunction {
1588
1942
  params,
1589
1943
  body,
1590
- span: Span { start: start_span.start, end },
1944
+ span: Span {
1945
+ start: start_span.start,
1946
+ end,
1947
+ },
1591
1948
  }))
1592
1949
  }
1593
1950
 
@@ -1651,7 +2008,11 @@ impl<'a> Parser<'a> {
1651
2008
  self.expect(TokenKind::RBrace)?; // }
1652
2009
  JsxAttrValue::Expr(expr)
1653
2010
  } else {
1654
- let s = self.expect(TokenKind::String)?.literal.clone().ok_or("Expected string")?;
2011
+ let s = self
2012
+ .expect(TokenKind::String)?
2013
+ .literal
2014
+ .clone()
2015
+ .ok_or("Expected string")?;
1655
2016
  JsxAttrValue::String(s)
1656
2017
  };
1657
2018
  props.push(JsxProp::Attr { name, value });
@@ -1662,7 +2023,12 @@ impl<'a> Parser<'a> {
1662
2023
  });
1663
2024
  }
1664
2025
  }
1665
- _ => return Err(format!("Unexpected token in JSX props: {:?}", self.peek_kind())),
2026
+ _ => {
2027
+ return Err(format!(
2028
+ "Unexpected token in JSX props: {:?}",
2029
+ self.peek_kind()
2030
+ ))
2031
+ }
1666
2032
  }
1667
2033
  }
1668
2034
  self.advance(); // consume >
@@ -1745,9 +2111,16 @@ impl<'a> Parser<'a> {
1745
2111
  // </ closing tag
1746
2112
  self.advance(); // <
1747
2113
  self.advance(); // /
1748
- let name = self.expect(TokenKind::Ident)?.literal.clone().ok_or("Expected tag name")?;
2114
+ let name = self
2115
+ .expect(TokenKind::Ident)?
2116
+ .literal
2117
+ .clone()
2118
+ .ok_or("Expected tag name")?;
1749
2119
  if name.as_ref() != close_tag {
1750
- return Err(format!("Mismatched JSX tag: expected </{}> got </{}>", close_tag, name));
2120
+ return Err(format!(
2121
+ "Mismatched JSX tag: expected </{}> got </{}>",
2122
+ close_tag, name
2123
+ ));
1751
2124
  }
1752
2125
  self.expect(TokenKind::Gt)?; // >
1753
2126
  return Ok(children);
@@ -1827,7 +2200,10 @@ impl<'a> Parser<'a> {
1827
2200
  self.advance();
1828
2201
  self.advance();
1829
2202
  let end = self.previous_span_end();
1830
- return Ok(Expr::JsxFragment { children, span: Span { start, end } });
2203
+ return Ok(Expr::JsxFragment {
2204
+ children,
2205
+ span: Span { start, end },
2206
+ });
1831
2207
  }
1832
2208
  }
1833
2209
  return Err("Expected </> to close fragment".to_string());
@@ -1929,4 +2305,3 @@ impl ExprSpan for Expr {
1929
2305
  }
1930
2306
  }
1931
2307
  }
1932
-