@tishlang/tish-format 1.0.13 → 2.0.2

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 (108) hide show
  1. package/Cargo.toml +2 -0
  2. package/bin/tish-format +0 -0
  3. package/crates/js_to_tish/src/transform/expr.rs +1 -0
  4. package/crates/tish/Cargo.toml +10 -2
  5. package/crates/tish/build.rs +21 -0
  6. package/crates/tish/src/cli_help.rs +15 -4
  7. package/crates/tish/src/main.rs +93 -21
  8. package/crates/tish/src/repl_completion.rs +0 -1
  9. package/crates/tish/tests/error_source_location.rs +36 -0
  10. package/crates/tish/tests/fixtures/runtime_error_location.tish +5 -0
  11. package/crates/tish/tests/fixtures/trycatch_runtime_errors.tish +15 -0
  12. package/crates/tish/tests/fixtures/tty_capability.tish +9 -0
  13. package/crates/tish/tests/integration_test.rs +402 -91
  14. package/crates/tish/tests/trycatch_runtime_errors.rs +45 -0
  15. package/crates/tish/tests/tty_capability.rs +43 -0
  16. package/crates/tish_ast/src/ast.rs +37 -8
  17. package/crates/tish_builtins/Cargo.toml +2 -0
  18. package/crates/tish_builtins/src/array.rs +375 -13
  19. package/crates/tish_builtins/src/collections.rs +481 -0
  20. package/crates/tish_builtins/src/construct.rs +59 -19
  21. package/crates/tish_builtins/src/date.rs +538 -0
  22. package/crates/tish_builtins/src/globals.rs +86 -6
  23. package/crates/tish_builtins/src/iterator.rs +129 -0
  24. package/crates/tish_builtins/src/lib.rs +5 -0
  25. package/crates/tish_builtins/src/number.rs +96 -0
  26. package/crates/tish_builtins/src/object.rs +2 -2
  27. package/crates/tish_builtins/src/string.rs +19 -20
  28. package/crates/tish_builtins/src/symbol.rs +1 -1
  29. package/crates/tish_builtins/src/typedarrays.rs +298 -0
  30. package/crates/tish_bytecode/src/chunk.rs +69 -1
  31. package/crates/tish_bytecode/src/compiler.rs +933 -89
  32. package/crates/tish_bytecode/src/encoding.rs +2 -0
  33. package/crates/tish_bytecode/src/lib.rs +2 -1
  34. package/crates/tish_bytecode/src/opcode.rs +47 -4
  35. package/crates/tish_bytecode/src/serialize.rs +31 -1
  36. package/crates/tish_compile/Cargo.toml +1 -0
  37. package/crates/tish_compile/src/check.rs +774 -0
  38. package/crates/tish_compile/src/codegen.rs +2334 -349
  39. package/crates/tish_compile/src/infer.rs +1395 -6
  40. package/crates/tish_compile/src/lib.rs +50 -8
  41. package/crates/tish_compile/src/resolve.rs +584 -21
  42. package/crates/tish_compile/src/types.rs +106 -2
  43. package/crates/tish_compile_js/src/codegen.rs +67 -0
  44. package/crates/tish_compile_js/src/tests_jsx.rs +64 -0
  45. package/crates/tish_core/Cargo.toml +7 -1
  46. package/crates/tish_core/src/console_style.rs +11 -1
  47. package/crates/tish_core/src/json.rs +81 -38
  48. package/crates/tish_core/src/lib.rs +3 -0
  49. package/crates/tish_core/src/shape.rs +85 -0
  50. package/crates/tish_core/src/value.rs +679 -25
  51. package/crates/tish_core/src/vmref.rs +13 -8
  52. package/crates/tish_cranelift/src/link.rs +17 -4
  53. package/crates/tish_cranelift_runtime/Cargo.toml +1 -0
  54. package/crates/tish_eval/Cargo.toml +6 -0
  55. package/crates/tish_eval/src/eval.rs +665 -117
  56. package/crates/tish_eval/src/http.rs +4 -1
  57. package/crates/tish_eval/src/natives.rs +165 -13
  58. package/crates/tish_eval/src/value.rs +31 -13
  59. package/crates/tish_eval/src/value_convert.rs +10 -4
  60. package/crates/tish_ffi/Cargo.toml +26 -0
  61. package/crates/tish_ffi/src/lib.rs +518 -0
  62. package/crates/tish_ffi/tests/fixtures/testmod/Cargo.toml +18 -0
  63. package/crates/tish_ffi/tests/fixtures/testmod/src/lib.rs +46 -0
  64. package/crates/tish_ffi/tests/loader.rs +65 -0
  65. package/crates/tish_fmt/Cargo.toml +1 -1
  66. package/crates/tish_fmt/src/lib.rs +61 -5
  67. package/crates/tish_lexer/src/lib.rs +397 -9
  68. package/crates/tish_lexer/src/token.rs +7 -0
  69. package/crates/tish_lint/src/lib.rs +2 -10
  70. package/crates/tish_lsp/src/import_goto.rs +2 -0
  71. package/crates/tish_lsp/src/main.rs +439 -26
  72. package/crates/tish_native/src/build.rs +55 -1
  73. package/crates/tish_opt/src/lib.rs +126 -23
  74. package/crates/tish_parser/src/lib.rs +55 -1
  75. package/crates/tish_parser/src/parser.rs +456 -34
  76. package/crates/tish_pg/src/lib.rs +3 -3
  77. package/crates/tish_resolve/src/lib.rs +99 -59
  78. package/crates/tish_runtime/Cargo.toml +4 -0
  79. package/crates/tish_runtime/src/http.rs +66 -17
  80. package/crates/tish_runtime/src/http_fetch.rs +29 -8
  81. package/crates/tish_runtime/src/http_hyper.rs +25 -2
  82. package/crates/tish_runtime/src/lib.rs +299 -44
  83. package/crates/tish_runtime/src/promise.rs +328 -18
  84. package/crates/tish_runtime/src/timers.rs +13 -7
  85. package/crates/tish_runtime/src/tty.rs +226 -0
  86. package/crates/tish_runtime/src/ws.rs +35 -18
  87. package/crates/tish_runtime/tests/fetch_readable_stream.rs +2 -2
  88. package/crates/tish_ui/src/jsx.rs +10 -0
  89. package/crates/tish_ui/src/runtime/hooks.rs +19 -15
  90. package/crates/tish_ui/src/runtime/mod.rs +15 -12
  91. package/crates/tish_vm/Cargo.toml +14 -1
  92. package/crates/tish_vm/src/jit.rs +1050 -0
  93. package/crates/tish_vm/src/lib.rs +2 -0
  94. package/crates/tish_vm/src/vm.rs +1546 -202
  95. package/crates/tish_vm/tests/concurrent_shared_state.rs +140 -0
  96. package/crates/tish_wasm/src/lib.rs +6 -2
  97. package/crates/tish_wasm_runtime/src/gpu.rs +17 -1
  98. package/crates/tishlang_cargo_bindgen/src/classify.rs +1 -3
  99. package/crates/tishlang_cargo_bindgen/src/lib.rs +2 -2
  100. package/crates/tishlang_cargo_bindgen/src/metadata.rs +1 -1
  101. package/justfile +8 -0
  102. package/package.json +2 -2
  103. package/platform/darwin-arm64/tish-fmt +0 -0
  104. package/platform/darwin-x64/tish-fmt +0 -0
  105. package/platform/linux-arm64/tish-fmt +0 -0
  106. package/platform/linux-x64/tish-fmt +0 -0
  107. package/platform/win32-x64/tish-fmt.exe +0 -0
  108. package/README.md +0 -138
@@ -1,5 +1,6 @@
1
1
  //! Recursive descent parser for Tish.
2
2
 
3
+ use std::collections::{HashMap, HashSet};
3
4
  use std::sync::Arc;
4
5
 
5
6
  /// Macro to generate single-operator binary parsing functions.
@@ -55,18 +56,112 @@ use tishlang_ast::{
55
56
  ArrayElement, ArrowBody, BinOp, CallArg, CompoundOp, DestructElement, DestructPattern,
56
57
  DestructProp, ExportDeclaration, Expr, FunParam, ImportSpecifier, JsxAttrValue, JsxChild,
57
58
  JsxProp, Literal, LogicalAssignOp, MemberProp, ObjectProp, Program, Span, Statement,
58
- TypeAnnotation, TypedParam, UnaryOp,
59
+ TypeAnnotation, TypeLiteral, TypedParam, UnaryOp,
59
60
  };
60
61
  use tishlang_lexer::{Token, TokenKind};
61
62
 
63
+ /// Mangle a generic instantiation `base<args>` into a Rust-ident-safe alias name (`Box__number`).
64
+ fn mangle_generic(base: &str, args: &[TypeAnnotation]) -> String {
65
+ let parts: Vec<String> = args.iter().map(mangle_type).collect();
66
+ format!("{}__{}", base, parts.join("_"))
67
+ }
68
+
69
+ fn mangle_type(t: &TypeAnnotation) -> String {
70
+ match t {
71
+ TypeAnnotation::Simple(s) => s.chars().map(|c| if c.is_alphanumeric() { c } else { '_' }).collect(),
72
+ TypeAnnotation::Array(inner) => format!("{}Arr", mangle_type(inner)),
73
+ TypeAnnotation::Tuple(es) => {
74
+ format!("Tup{}", es.iter().map(mangle_type).collect::<Vec<_>>().join(""))
75
+ }
76
+ TypeAnnotation::Object(_) => "Obj".to_string(),
77
+ TypeAnnotation::Union(_) => "Un".to_string(),
78
+ TypeAnnotation::Intersection(_) => "Is".to_string(),
79
+ TypeAnnotation::Function { .. } => "Fn".to_string(),
80
+ TypeAnnotation::Literal(_) => "Lit".to_string(),
81
+ }
82
+ }
83
+
84
+ /// Substitute generic type parameters with their concrete arguments throughout a type body.
85
+ fn subst_type(t: &TypeAnnotation, map: &HashMap<&str, &TypeAnnotation>) -> TypeAnnotation {
86
+ match t {
87
+ TypeAnnotation::Simple(s) => map
88
+ .get(s.as_ref())
89
+ .map(|rep| (*rep).clone())
90
+ .unwrap_or_else(|| t.clone()),
91
+ TypeAnnotation::Array(inner) => TypeAnnotation::Array(Box::new(subst_type(inner, map))),
92
+ TypeAnnotation::Object(fields) => TypeAnnotation::Object(
93
+ fields.iter().map(|(k, v)| (k.clone(), subst_type(v, map))).collect(),
94
+ ),
95
+ TypeAnnotation::Tuple(es) => {
96
+ TypeAnnotation::Tuple(es.iter().map(|e| subst_type(e, map)).collect())
97
+ }
98
+ TypeAnnotation::Union(es) => {
99
+ TypeAnnotation::Union(es.iter().map(|e| subst_type(e, map)).collect())
100
+ }
101
+ TypeAnnotation::Intersection(es) => {
102
+ TypeAnnotation::Intersection(es.iter().map(|e| subst_type(e, map)).collect())
103
+ }
104
+ TypeAnnotation::Function { params, returns } => TypeAnnotation::Function {
105
+ params: params.iter().map(|p| subst_type(p, map)).collect(),
106
+ returns: Box::new(subst_type(returns, map)),
107
+ },
108
+ TypeAnnotation::Literal(_) => t.clone(),
109
+ }
110
+ }
111
+
62
112
  pub struct Parser<'a> {
63
113
  tokens: &'a [Token],
64
114
  pos: usize,
115
+ /// Outstanding `>` owed to enclosing generic-arg lists after a `>>` (`Shr`) token was split,
116
+ /// so nested `Array<Array<T>>` closes correctly (tish lexes `>>` as one token).
117
+ gt_debt: u32,
118
+ /// Generic `type`/`interface` decls (`type Box<T> = …`) → (type-param names, body), for
119
+ /// monomorphizing a reference `Box<number>` into a concrete native struct.
120
+ generic_aliases: HashMap<String, (Vec<Arc<str>>, TypeAnnotation)>,
121
+ /// Synthetic specialized aliases (e.g. `type Box__number = { value: number }`) generated for
122
+ /// each distinct `Generic<Args>` reference; appended to the program at the end.
123
+ generic_specializations: Vec<Statement>,
124
+ /// Names of specializations already generated (dedup).
125
+ generic_done: HashSet<String>,
65
126
  }
66
127
 
67
128
  impl<'a> Parser<'a> {
68
129
  pub fn new(tokens: &'a [Token]) -> Self {
69
- Self { tokens, pos: 0 }
130
+ Self {
131
+ tokens,
132
+ pos: 0,
133
+ gt_debt: 0,
134
+ generic_aliases: HashMap::new(),
135
+ generic_specializations: Vec::new(),
136
+ generic_done: HashSet::new(),
137
+ }
138
+ }
139
+
140
+ /// Close one generic-arg `>`: use a previously-split `>>` debt, consume a `>`, or split a
141
+ /// `>>` (consuming it and owing one `>` to the parent). Returns false if there's no closer.
142
+ fn try_close_angle(&mut self) -> bool {
143
+ if self.gt_debt > 0 {
144
+ self.gt_debt -= 1;
145
+ return true;
146
+ }
147
+ match self.peek_kind() {
148
+ Some(TokenKind::Gt) => {
149
+ self.advance();
150
+ true
151
+ }
152
+ Some(TokenKind::Shr) => {
153
+ self.advance();
154
+ self.gt_debt += 1;
155
+ true
156
+ }
157
+ Some(TokenKind::UShr) => {
158
+ // `>>>` closing three generic args, e.g. `Foo<Bar<Baz<T>>>`.
159
+ self.advance();
160
+ self.gt_debt += 2;
161
+ true
162
+ }
163
+ _ => false,
164
+ }
70
165
  }
71
166
 
72
167
  fn peek(&self) -> Option<&Token> {
@@ -99,11 +194,20 @@ impl<'a> Parser<'a> {
99
194
  }
100
195
  }
101
196
 
102
- /// After `.` / `?.`, allow `type` as a member name (`TokenKind::Type`); see `docs/js-emit-philosophy.md`.
197
+ /// After `.` / `?.`, allow contextual keywords as member names. In JS any `IdentifierName`
198
+ /// (including reserved words) is a valid property name — `arr.of`, `x.as`, `o.in`, `o.type` —
199
+ /// but the lexer emits dedicated keyword tokens for these, so they must be accepted explicitly
200
+ /// here. (`TypedArray.of` is the motivating case.) See `docs/js-emit-philosophy.md`.
103
201
  fn expect_ident_or_type_member_name(&mut self) -> Result<&Token, String> {
104
202
  match self.peek_kind() {
105
203
  Some(TokenKind::Ident) => self.expect(TokenKind::Ident),
106
204
  Some(TokenKind::Type) => self.expect(TokenKind::Type),
205
+ Some(TokenKind::Of) => self.expect(TokenKind::Of),
206
+ Some(TokenKind::As) => self.expect(TokenKind::As),
207
+ Some(TokenKind::In) => self.expect(TokenKind::In),
208
+ // `delete` is a keyword (the operator) but also a valid property name —
209
+ // `Set`/`Map` expose `.delete(...)`. Issue #40.
210
+ Some(TokenKind::Delete) => self.expect(TokenKind::Delete),
107
211
  other => Err(format!(
108
212
  "Expected property name after `.` or `?.`, got {:?}",
109
213
  other
@@ -111,6 +215,26 @@ impl<'a> Parser<'a> {
111
215
  }
112
216
  }
113
217
 
218
+ /// Accept a plain identifier, or the contextual keywords `fn` / `type` used as an
219
+ /// identifier. JS treats `fn` as an ordinary identifier and `type` as only contextually
220
+ /// reserved, so both are valid binding / parameter names and value references (issue #55).
221
+ /// All three carry their spelling in `.literal`. Statement-leading `fn` / `type`
222
+ /// (function declarations / type aliases) are matched earlier in `parse_statement`, so this
223
+ /// only fires in identifier positions.
224
+ fn expect_identifier_name(&mut self) -> Result<&Token, String> {
225
+ let t = self
226
+ .advance()
227
+ .ok_or_else(|| "Expected identifier, got EOF".to_string())?;
228
+ if matches!(
229
+ t.kind,
230
+ TokenKind::Ident | TokenKind::Fn | TokenKind::Type
231
+ ) {
232
+ Ok(t)
233
+ } else {
234
+ Err(format!("Expected Ident, got {:?} at {:?}", t.kind, t.span))
235
+ }
236
+ }
237
+
114
238
  fn span_end(&self, start: (usize, usize)) -> Span {
115
239
  let end = self.peek().map(|t| t.span.start).unwrap_or(start);
116
240
  Span { start, end }
@@ -125,6 +249,13 @@ impl<'a> Parser<'a> {
125
249
  }
126
250
  statements.push(self.parse_statement()?);
127
251
  }
252
+ // Prepend the synthetic monomorphized aliases (`type Box__number = …`) so they're declared
253
+ // before any use, for alias resolution + native struct emission.
254
+ if !self.generic_specializations.is_empty() {
255
+ let mut out = std::mem::take(&mut self.generic_specializations);
256
+ out.append(&mut statements);
257
+ statements = out;
258
+ }
128
259
  Ok(Program { statements })
129
260
  }
130
261
 
@@ -173,6 +304,7 @@ impl<'a> Parser<'a> {
173
304
  TokenKind::Export => self.parse_export()?,
174
305
  TokenKind::Type => self.parse_type_alias()?,
175
306
  TokenKind::Declare => self.parse_declare()?,
307
+ TokenKind::Interface => self.parse_interface()?,
176
308
  _ => {
177
309
  let expr = self.parse_expr()?;
178
310
  let span_end = expr.span().end;
@@ -270,7 +402,37 @@ impl<'a> Parser<'a> {
270
402
  self.expect(TokenKind::Const)?.span.start
271
403
  };
272
404
 
273
- // Check for destructuring pattern
405
+ // First declarator keeps the `let`/`const`-anchored span (single-decl is
406
+ // the overwhelmingly common case and stays byte-identical to before).
407
+ let first = self.parse_one_declarator(mutable, span_start)?;
408
+ if !matches!(self.peek_kind(), Some(TokenKind::Comma)) {
409
+ return Ok(first);
410
+ }
411
+
412
+ // Comma-separated declarators: `let a = 1, b = 2, c`. Each lowers to its
413
+ // own VarDecl inside a transparent `Multi` group (no new scope), so it
414
+ // composes anywhere a single statement is expected (incl. `for` init).
415
+ let mut statements = vec![first];
416
+ while matches!(self.peek_kind(), Some(TokenKind::Comma)) {
417
+ self.advance(); // consume ','
418
+ let decl_start = self.peek().map(|t| t.span.start).unwrap_or(span_start);
419
+ statements.push(self.parse_one_declarator(mutable, decl_start)?);
420
+ }
421
+ Ok(Statement::Multi {
422
+ statements,
423
+ span: self.span_end(span_start),
424
+ })
425
+ }
426
+
427
+ /// Parse one declarator — `ident[: Type] [= init]` or `pattern = init` — into
428
+ /// its own statement. The leading `let`/`const` keyword is consumed by the
429
+ /// caller; `span_start` anchors this declarator's span.
430
+ fn parse_one_declarator(
431
+ &mut self,
432
+ mutable: bool,
433
+ span_start: (usize, usize),
434
+ ) -> Result<Statement, String> {
435
+ // Destructuring pattern declarator.
274
436
  if matches!(
275
437
  self.peek_kind(),
276
438
  Some(TokenKind::LBracket) | Some(TokenKind::LBrace)
@@ -286,7 +448,7 @@ impl<'a> Parser<'a> {
286
448
  });
287
449
  }
288
450
 
289
- let name_tok = self.expect(TokenKind::Ident)?;
451
+ let name_tok = self.expect_identifier_name()?;
290
452
  let name_span = Span {
291
453
  start: name_tok.span.start,
292
454
  end: name_tok.span.end,
@@ -454,7 +616,7 @@ impl<'a> Parser<'a> {
454
616
  default,
455
617
  });
456
618
  }
457
- let param_tok = self.expect(TokenKind::Ident)?;
619
+ let param_tok = self.expect_identifier_name()?;
458
620
  let name_span = Span {
459
621
  start: param_tok.span.start,
460
622
  end: param_tok.span.end,
@@ -480,23 +642,88 @@ impl<'a> Parser<'a> {
480
642
  }))
481
643
  }
482
644
 
483
- /// Parse a type annotation (number, string, T[], {a: T}, etc.)
484
- fn parse_type_annotation(&mut self) -> Result<TypeAnnotation, String> {
485
- let base = self.parse_type_primary()?;
645
+ /// Parse a generic type-parameter list `<T, U, …>` on a `fn` / `type` declaration, returning the
646
+ /// parameter names. On functions the names are ignored (generic fns run gradually/boxed); on
647
+ /// `type`/`interface` they drive struct monomorphization (`Box<number>` → a native struct).
648
+ fn parse_type_params(&mut self) -> Result<Vec<Arc<str>>, String> {
649
+ let mut params = Vec::new();
650
+ if matches!(self.peek_kind(), Some(TokenKind::Lt)) {
651
+ self.advance(); // <
652
+ while !matches!(self.peek_kind(), Some(TokenKind::Gt)) {
653
+ let tok = self.expect(TokenKind::Ident)?;
654
+ if let Some(n) = &tok.literal {
655
+ params.push(Arc::from(n.as_ref()));
656
+ }
657
+ if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
658
+ self.advance();
659
+ } else {
660
+ break;
661
+ }
662
+ }
663
+ self.expect(TokenKind::Gt)?; // >
664
+ }
665
+ Ok(params)
666
+ }
486
667
 
487
- // Check for array suffix: T[]
488
- if matches!(self.peek_kind(), Some(TokenKind::LBracket)) {
489
- self.advance(); // [
490
- self.expect(TokenKind::RBracket)?; // ]
491
- return Ok(TypeAnnotation::Array(Box::new(base)));
668
+ /// Specialize a generic struct reference `base<args>` into a concrete synthetic alias name
669
+ /// (e.g. `Box__number`), emitting `type Box__number = { value: number }` once per instantiation
670
+ /// so it lowers to a native struct. Returns `None` if `base` isn't a known generic alias or the
671
+ /// arity mismatches (caller then falls back to erasing the args).
672
+ fn monomorphize_generic(&mut self, base: &str, args: &[TypeAnnotation]) -> Option<String> {
673
+ let (params, body) = self.generic_aliases.get(base)?.clone();
674
+ if params.len() != args.len() {
675
+ return None;
492
676
  }
677
+ let spec_name = mangle_generic(base, args);
678
+ if self.generic_done.insert(spec_name.clone()) {
679
+ let subst: HashMap<&str, &TypeAnnotation> =
680
+ params.iter().map(|p| p.as_ref()).zip(args.iter()).collect();
681
+ let concrete = subst_type(&body, &subst);
682
+ let z = Span {
683
+ start: (0, 0),
684
+ end: (0, 0),
685
+ };
686
+ self.generic_specializations.push(Statement::TypeAlias {
687
+ name: Arc::from(spec_name.as_str()),
688
+ name_span: z,
689
+ ty: concrete,
690
+ span: z,
691
+ });
692
+ }
693
+ Some(spec_name)
694
+ }
493
695
 
494
- // Check for union: T | U
696
+ /// Parse a generic type-argument list `<T, U, …>` on a type reference (`Array<number>`,
697
+ /// `Map<string, number>`). Nested `Array<Array<T>>` works because tish has no `>>` token.
698
+ fn parse_type_args(&mut self) -> Result<Vec<TypeAnnotation>, String> {
699
+ self.expect(TokenKind::Lt)?; // <
700
+ let mut args = Vec::new();
701
+ if !self.try_close_angle() {
702
+ loop {
703
+ args.push(self.parse_type_annotation()?);
704
+ if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
705
+ self.advance();
706
+ continue;
707
+ }
708
+ break;
709
+ }
710
+ if !self.try_close_angle() {
711
+ return Err("expected `>` to close type arguments".to_string());
712
+ }
713
+ }
714
+ Ok(args)
715
+ }
716
+
717
+ /// Parse a type annotation (number, string, T[], T?, {a: T}, A | B, A & B, Array<T>, etc.)
718
+ fn parse_type_annotation(&mut self) -> Result<TypeAnnotation, String> {
719
+ let base = self.parse_type_intersection()?;
720
+
721
+ // Union: T | U | ... (binds looser than `&`)
495
722
  if matches!(self.peek_kind(), Some(TokenKind::BitOr)) {
496
723
  let mut types = vec![base];
497
724
  while matches!(self.peek_kind(), Some(TokenKind::BitOr)) {
498
725
  self.advance(); // |
499
- types.push(self.parse_type_primary()?);
726
+ types.push(self.parse_type_intersection()?);
500
727
  }
501
728
  return Ok(TypeAnnotation::Union(types));
502
729
  }
@@ -504,12 +731,65 @@ impl<'a> Parser<'a> {
504
731
  Ok(base)
505
732
  }
506
733
 
734
+ /// `A & B & …` intersection (binds tighter than `|`).
735
+ fn parse_type_intersection(&mut self) -> Result<TypeAnnotation, String> {
736
+ let base = self.parse_type_postfix()?;
737
+ if matches!(self.peek_kind(), Some(TokenKind::BitAnd)) {
738
+ let mut types = vec![base];
739
+ while matches!(self.peek_kind(), Some(TokenKind::BitAnd)) {
740
+ self.advance(); // &
741
+ types.push(self.parse_type_postfix()?);
742
+ }
743
+ return Ok(TypeAnnotation::Intersection(types));
744
+ }
745
+ Ok(base)
746
+ }
747
+
748
+ /// A primary type plus any postfix `[]` (array) and `?` (optional, `T? === T | null`),
749
+ /// chained: `T[]`, `T[][]`, `T?`, `T?[]`, …
750
+ fn parse_type_postfix(&mut self) -> Result<TypeAnnotation, String> {
751
+ let mut t = self.parse_type_primary()?;
752
+ loop {
753
+ match self.peek_kind() {
754
+ Some(TokenKind::LBracket) => {
755
+ self.advance(); // [
756
+ self.expect(TokenKind::RBracket)?; // ]
757
+ t = TypeAnnotation::Array(Box::new(t));
758
+ }
759
+ Some(TokenKind::Question) => {
760
+ self.advance(); // ?
761
+ t = TypeAnnotation::Union(vec![t, TypeAnnotation::Simple("null".into())]);
762
+ }
763
+ _ => break,
764
+ }
765
+ }
766
+ Ok(t)
767
+ }
768
+
507
769
  /// Parse a primary type (identifier, object, or function type)
508
770
  fn parse_type_primary(&mut self) -> Result<TypeAnnotation, String> {
509
771
  match self.peek_kind() {
510
772
  Some(TokenKind::Ident) => {
511
773
  let tok = self.advance().ok_or("Expected type name")?;
512
774
  let name = tok.literal.clone().ok_or("Expected type name")?;
775
+ // Generic reference `Name<Args>`: `Array<T>` desugars to the native `T[]`; other
776
+ // generic refs erase their args (the base name resolves to its alias, whose type
777
+ // params already act as unknown -> `Value`).
778
+ if matches!(self.peek_kind(), Some(TokenKind::Lt)) {
779
+ let args = self.parse_type_args()?;
780
+ if name.as_ref() == "Array" && args.len() == 1 {
781
+ return Ok(TypeAnnotation::Array(Box::new(
782
+ args.into_iter().next().unwrap(),
783
+ )));
784
+ }
785
+ // Monomorphize a generic struct ref `Box<number>` into a synthetic concrete
786
+ // alias `Box__number` (a native struct). Falls back to erasing the args when
787
+ // `name` isn't a known generic alias (e.g. forward reference) or arity mismatches.
788
+ if let Some(spec) = self.monomorphize_generic(name.as_ref(), &args) {
789
+ return Ok(TypeAnnotation::Simple(Arc::from(spec.as_str())));
790
+ }
791
+ return Ok(TypeAnnotation::Simple(name));
792
+ }
513
793
  Ok(TypeAnnotation::Simple(name))
514
794
  }
515
795
  Some(TokenKind::Type | TokenKind::Declare) => {
@@ -588,6 +868,39 @@ impl<'a> Parser<'a> {
588
868
  returns: Box::new(returns),
589
869
  })
590
870
  }
871
+ // Tuple type: [T1, T2, ...]
872
+ Some(TokenKind::LBracket) => {
873
+ self.advance(); // [
874
+ let mut elems = Vec::new();
875
+ while !matches!(self.peek_kind(), Some(TokenKind::RBracket)) {
876
+ elems.push(self.parse_type_annotation()?);
877
+ if !matches!(self.peek_kind(), Some(TokenKind::RBracket)) {
878
+ self.expect(TokenKind::Comma)?;
879
+ }
880
+ }
881
+ self.expect(TokenKind::RBracket)?;
882
+ Ok(TypeAnnotation::Tuple(elems))
883
+ }
884
+ // Literal types: "foo", 42, true, false
885
+ Some(TokenKind::String) => {
886
+ let tok = self.advance().ok_or("Expected string literal type")?;
887
+ let s = tok.literal.clone().ok_or("Expected string literal")?;
888
+ Ok(TypeAnnotation::Literal(TypeLiteral::Str(s)))
889
+ }
890
+ Some(TokenKind::Number) => {
891
+ let tok = self.advance().ok_or("Expected number literal type")?;
892
+ let s = tok.literal.as_ref().ok_or("Expected number literal")?;
893
+ let n: f64 = s.parse().map_err(|_| format!("Invalid number: {}", s))?;
894
+ Ok(TypeAnnotation::Literal(TypeLiteral::Num(n)))
895
+ }
896
+ Some(TokenKind::True) => {
897
+ self.advance();
898
+ Ok(TypeAnnotation::Literal(TypeLiteral::Bool(true)))
899
+ }
900
+ Some(TokenKind::False) => {
901
+ self.advance();
902
+ Ok(TypeAnnotation::Literal(TypeLiteral::Bool(false)))
903
+ }
591
904
  _ => Err("Expected type annotation".to_string()),
592
905
  }
593
906
  }
@@ -600,6 +913,7 @@ impl<'a> Parser<'a> {
600
913
  end: name_tok.span.end,
601
914
  };
602
915
  let name = name_tok.literal.clone().ok_or("Expected function name")?;
916
+ self.parse_type_params()?; // generic `fn f<T, U>(…)` — fn type params run gradually (boxed)
603
917
  self.expect(TokenKind::LParen)?;
604
918
  let mut params = Vec::with_capacity(4);
605
919
  let mut rest_param = None;
@@ -695,8 +1009,62 @@ impl<'a> Parser<'a> {
695
1009
  end: name_tok.span.end,
696
1010
  };
697
1011
  let name = name_tok.literal.clone().ok_or("Expected type alias name")?;
1012
+ let type_params = self.parse_type_params()?;
698
1013
  self.expect(TokenKind::Assign)?;
699
1014
  let ty = self.parse_type_annotation()?;
1015
+ if !type_params.is_empty() {
1016
+ self.generic_aliases
1017
+ .insert(name.to_string(), (type_params, ty.clone()));
1018
+ }
1019
+ Ok(Statement::TypeAlias {
1020
+ name,
1021
+ name_span,
1022
+ ty,
1023
+ span: self.span_end(span_start),
1024
+ })
1025
+ }
1026
+
1027
+ /// `interface Name { k: T, ... }` — desugared to `type Name = { ... }` so the checker
1028
+ /// (structural matching) and codegen (native `TishStruct_*`) treat it exactly like an
1029
+ /// object-type alias. (`extends` is not yet supported.)
1030
+ fn parse_interface(&mut self) -> Result<Statement, String> {
1031
+ let span_start = self.expect(TokenKind::Interface)?.span.start;
1032
+ let name_tok = self.expect(TokenKind::Ident)?;
1033
+ let name_span = Span {
1034
+ start: name_tok.span.start,
1035
+ end: name_tok.span.end,
1036
+ };
1037
+ let name = name_tok.literal.clone().ok_or("Expected interface name")?;
1038
+ let type_params = self.parse_type_params()?;
1039
+
1040
+ // `extends Parent1, Parent2` — desugar to an intersection of the parents with the body, so
1041
+ // the inherited fields participate in structural checking + native struct emission.
1042
+ let mut parents: Vec<TypeAnnotation> = Vec::new();
1043
+ if matches!(self.peek_kind(), Some(TokenKind::Ident))
1044
+ && self.peek().and_then(|t| t.literal.as_deref()) == Some("extends")
1045
+ {
1046
+ self.advance(); // extends
1047
+ loop {
1048
+ parents.push(self.parse_type_postfix()?);
1049
+ if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
1050
+ self.advance();
1051
+ continue;
1052
+ }
1053
+ break;
1054
+ }
1055
+ }
1056
+
1057
+ let body = self.parse_type_annotation()?;
1058
+ let ty = if parents.is_empty() {
1059
+ body
1060
+ } else {
1061
+ parents.push(body);
1062
+ TypeAnnotation::Intersection(parents)
1063
+ };
1064
+ if !type_params.is_empty() {
1065
+ self.generic_aliases
1066
+ .insert(name.to_string(), (type_params, ty.clone()));
1067
+ }
700
1068
  Ok(Statement::TypeAlias {
701
1069
  name,
702
1070
  name_span,
@@ -767,6 +1135,7 @@ impl<'a> Parser<'a> {
767
1135
  end: name_tok.span.end,
768
1136
  };
769
1137
  let name = name_tok.literal.clone().ok_or("Expected function name")?;
1138
+ self.parse_type_params()?; // generic `fn f<T, U>(…)` — fn type params run gradually (boxed)
770
1139
  self.expect(TokenKind::LParen)?;
771
1140
  let mut params = Vec::with_capacity(4);
772
1141
  let mut rest_param = None;
@@ -899,17 +1268,33 @@ impl<'a> Parser<'a> {
899
1268
  } else {
900
1269
  None
901
1270
  };
902
- if matches!(self.peek_kind(), Some(TokenKind::Semicolon)) {
903
- self.advance();
904
- }
905
- Some(Box::new(Statement::VarDecl {
1271
+ let first = Statement::VarDecl {
906
1272
  name,
907
1273
  name_span,
908
1274
  mutable,
909
1275
  type_ann,
910
1276
  init: init_expr,
911
1277
  span: self.span_end(var_span_start),
912
- }))
1278
+ };
1279
+ // Comma-separated for-init declarators: `for (let i = 0, n = len; ...)`.
1280
+ let decl = if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
1281
+ let mut statements = vec![first];
1282
+ while matches!(self.peek_kind(), Some(TokenKind::Comma)) {
1283
+ self.advance();
1284
+ let decl_start = self.peek().map(|t| t.span.start).unwrap_or(var_span_start);
1285
+ statements.push(self.parse_one_declarator(mutable, decl_start)?);
1286
+ }
1287
+ Statement::Multi {
1288
+ statements,
1289
+ span: self.span_end(var_span_start),
1290
+ }
1291
+ } else {
1292
+ first
1293
+ };
1294
+ if matches!(self.peek_kind(), Some(TokenKind::Semicolon)) {
1295
+ self.advance();
1296
+ }
1297
+ Some(Box::new(decl))
913
1298
  } else if matches!(self.peek_kind(), Some(TokenKind::Semicolon)) {
914
1299
  None
915
1300
  } else {
@@ -960,9 +1345,22 @@ impl<'a> Parser<'a> {
960
1345
 
961
1346
  fn parse_return(&mut self) -> Result<Statement, String> {
962
1347
  let span_start = self.expect(TokenKind::Return)?.span.start;
963
- let value = if matches!(self.peek_kind(), Some(TokenKind::Semicolon))
964
- || matches!(self.peek_kind(), Some(TokenKind::Dedent))
965
- || matches!(self.peek_kind(), Some(TokenKind::RBrace))
1348
+ // JS restricted production: `return [no LineTerminator here] Expression`.
1349
+ // A line break between `return` and its argument inserts a semicolon, so
1350
+ // `return` alone is `return null`. The lexer emits no token for a same-indent
1351
+ // line break (only Indent/Dedent on level *changes*), so a braceless
1352
+ // `if (c) return` followed by a statement on the next line would otherwise
1353
+ // swallow that statement as the return value (#96). Detect the line break by
1354
+ // comparing the next token's line to the `return` keyword's line.
1355
+ let next_on_new_line = self
1356
+ .peek()
1357
+ .map(|t| t.span.start.0 > span_start.0)
1358
+ .unwrap_or(true);
1359
+ let value = if next_on_new_line
1360
+ || matches!(
1361
+ self.peek_kind(),
1362
+ Some(TokenKind::Semicolon | TokenKind::Dedent | TokenKind::RBrace)
1363
+ )
966
1364
  || self.peek_kind().is_none()
967
1365
  {
968
1366
  None
@@ -1103,9 +1501,9 @@ impl<'a> Parser<'a> {
1103
1501
  .literal
1104
1502
  .clone()
1105
1503
  .ok_or("Expected identifier in import")?;
1106
- let (alias, alias_span) = if matches!(self.peek_kind(), Some(TokenKind::Ident))
1107
- && self.peek().and_then(|t| t.literal.as_deref()) == Some("as")
1108
- {
1504
+ // `as` is a dedicated keyword token (also used for casts); in import-specifier
1505
+ // position it introduces a rename: `{ foo as bar }`.
1506
+ let (alias, alias_span) = if matches!(self.peek_kind(), Some(TokenKind::As)) {
1109
1507
  self.advance(); // consume 'as'
1110
1508
  let alias_tok = self.expect(TokenKind::Ident)?;
1111
1509
  let asp = Span {
@@ -1139,10 +1537,7 @@ impl<'a> Parser<'a> {
1139
1537
  } else if matches!(self.peek_kind(), Some(TokenKind::Star)) {
1140
1538
  // Namespace: import * as M from "..."
1141
1539
  self.advance();
1142
- let as_tok = self.expect(TokenKind::Ident)?;
1143
- if as_tok.literal.as_deref() != Some("as") {
1144
- return Err("Expected 'as' after '*' in namespace import".to_string());
1145
- }
1540
+ self.expect(TokenKind::As)?;
1146
1541
  let alias_tok = self.expect(TokenKind::Ident)?;
1147
1542
  let name_span = Span {
1148
1543
  start: alias_tok.span.start,
@@ -1376,7 +1771,7 @@ impl<'a> Parser<'a> {
1376
1771
  binary_single_op!(parse_bit_xor, parse_bit_and, BitXor, BinOp::BitXor);
1377
1772
  binary_single_op!(parse_bit_and, parse_shift, BitAnd, BinOp::BitAnd);
1378
1773
 
1379
- binary_multi_op!(parse_shift, parse_equality, Shl => BinOp::Shl, Shr => BinOp::Shr);
1774
+ binary_multi_op!(parse_shift, parse_equality, Shl => BinOp::Shl, Shr => BinOp::Shr, UShr => BinOp::UShr);
1380
1775
  binary_multi_op!(parse_equality, parse_comparison,
1381
1776
  StrictEq => BinOp::StrictEq, StrictNe => BinOp::StrictNe,
1382
1777
  Eq => BinOp::Eq, Ne => BinOp::Ne);
@@ -1448,6 +1843,19 @@ impl<'a> Parser<'a> {
1448
1843
  },
1449
1844
  });
1450
1845
  }
1846
+ Some(TokenKind::Delete) => {
1847
+ let span_start = self.peek().map(|t| t.span.start).unwrap_or((0, 0));
1848
+ self.advance();
1849
+ let target = self.parse_unary()?;
1850
+ let end = target.span().end;
1851
+ return Ok(Expr::Delete {
1852
+ target: Box::new(target),
1853
+ span: Span {
1854
+ start: span_start,
1855
+ end,
1856
+ },
1857
+ });
1858
+ }
1451
1859
  Some(TokenKind::Await) => {
1452
1860
  let span_start = self.peek().map(|t| t.span.start).unwrap_or((0, 0));
1453
1861
  self.advance();
@@ -1574,6 +1982,13 @@ impl<'a> Parser<'a> {
1574
1982
  };
1575
1983
  while let Some(kind) = self.peek_kind() {
1576
1984
  match kind {
1985
+ // `expr as Type` — a type assertion. Gradual + erased: consume the type and keep the
1986
+ // expression unchanged (no runtime effect; the checker is already lenient on what it
1987
+ // can't prove, so the assertion's only job — silencing a strict error — is moot).
1988
+ TokenKind::As => {
1989
+ self.advance(); // as
1990
+ self.parse_type_annotation()?;
1991
+ }
1577
1992
  TokenKind::LParen => {
1578
1993
  self.advance();
1579
1994
  let mut args = Vec::new();
@@ -1699,7 +2114,10 @@ impl<'a> Parser<'a> {
1699
2114
  value: Literal::Null,
1700
2115
  span,
1701
2116
  }),
1702
- TokenKind::Ident => {
2117
+ // `fn` / `type` as a value reference or single-param arrow head (issue #55).
2118
+ // `fn`/`type` function-expressions don't exist and statement-leading decls are
2119
+ // handled in parse_statement, so treating them as identifiers here is additive.
2120
+ TokenKind::Ident | TokenKind::Fn | TokenKind::Type => {
1703
2121
  let name = t.literal.clone().ok_or("Expected ident")?;
1704
2122
  // Check if this is a single-param arrow function: x => ...
1705
2123
  if matches!(self.peek_kind(), Some(TokenKind::Arrow)) {
@@ -1875,7 +2293,10 @@ impl<'a> Parser<'a> {
1875
2293
  }
1876
2294
  }
1877
2295
  }
1878
- _ => Err(format!("Unexpected token: {:?}", t.kind)),
2296
+ // Include the token span (matching `expect`'s `at {:?}` convention) so error consumers
2297
+ // — notably the LSP's `parse_error_pos` — can place the diagnostic at the real location
2298
+ // instead of falling back to (0, 0) / top-of-file.
2299
+ _ => Err(format!("Unexpected token: {:?} at {:?}", t.kind, t.span)),
1879
2300
  }
1880
2301
  }
1881
2302
 
@@ -2285,6 +2706,7 @@ impl ExprSpan for Expr {
2285
2706
  Expr::Object { span, .. } => *span,
2286
2707
  Expr::Assign { span, .. } => *span,
2287
2708
  Expr::TypeOf { span, .. } => *span,
2709
+ Expr::Delete { span, .. } => *span,
2288
2710
  Expr::PostfixInc { span, .. } => *span,
2289
2711
  Expr::PostfixDec { span, .. } => *span,
2290
2712
  Expr::PrefixInc { span, .. } => *span,