@tishlang/tish 1.7.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.
- package/Cargo.toml +1 -0
- package/README.md +2 -0
- package/bin/tish +0 -0
- package/crates/js_to_tish/src/transform/expr.rs +28 -8
- package/crates/js_to_tish/src/transform/stmt.rs +49 -22
- package/crates/tish/Cargo.toml +15 -5
- package/crates/tish/src/cargo_native_registry.rs +29 -0
- package/crates/tish/src/cli_help.rs +16 -10
- package/crates/tish/src/main.rs +87 -32
- package/crates/tish/src/repl_completion.rs +3 -3
- package/crates/tish/tests/cargo_example_compile.rs +1 -1
- package/crates/tish/tests/integration_test.rs +19 -7
- package/crates/tish/tests/shortcircuit.rs +1 -1
- package/crates/tish_ast/src/ast.rs +80 -9
- package/crates/tish_build_utils/Cargo.toml +4 -0
- package/crates/tish_build_utils/src/lib.rs +105 -2
- package/crates/tish_builtins/Cargo.toml +5 -1
- package/crates/tish_builtins/src/array.rs +13 -12
- package/crates/tish_builtins/src/construct.rs +34 -33
- package/crates/tish_builtins/src/globals.rs +12 -11
- package/crates/tish_builtins/src/helpers.rs +2 -1
- package/crates/tish_builtins/src/object.rs +3 -2
- package/crates/tish_builtins/src/string.rs +73 -3
- package/crates/tish_bytecode/src/compiler.rs +12 -14
- package/crates/tish_bytecode/src/opcode.rs +12 -3
- package/crates/tish_compile/Cargo.toml +1 -0
- package/crates/tish_compile/src/codegen.rs +745 -199
- package/crates/tish_compile/src/infer.rs +6 -0
- package/crates/tish_compile/src/lib.rs +4 -3
- package/crates/tish_compile/src/resolve.rs +180 -82
- package/crates/tish_compile/src/types.rs +175 -11
- package/crates/tish_compile_js/Cargo.toml +1 -0
- package/crates/tish_compile_js/src/codegen.rs +152 -29
- package/crates/tish_compile_js/src/lib.rs +3 -1
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +31 -12
- package/crates/tish_core/Cargo.toml +8 -0
- package/crates/tish_core/src/json.rs +102 -53
- package/crates/tish_core/src/lib.rs +3 -1
- package/crates/tish_core/src/macros.rs +5 -5
- package/crates/tish_core/src/value.rs +53 -15
- package/crates/tish_core/src/vmref.rs +178 -0
- package/crates/tish_eval/Cargo.toml +17 -2
- package/crates/tish_eval/src/eval.rs +90 -28
- package/crates/tish_eval/src/http.rs +61 -0
- package/crates/tish_eval/src/lib.rs +3 -3
- package/crates/tish_eval/src/natives.rs +41 -0
- package/crates/tish_eval/src/value.rs +7 -3
- package/crates/tish_eval/src/value_convert.rs +13 -5
- package/crates/tish_fmt/src/lib.rs +120 -30
- package/crates/tish_lexer/src/lib.rs +20 -5
- package/crates/tish_lexer/src/token.rs +4 -0
- package/crates/tish_llvm/src/lib.rs +3 -1
- package/crates/tish_lsp/Cargo.toml +4 -1
- package/crates/tish_lsp/README.md +1 -1
- package/crates/tish_lsp/src/builtin_goto.rs +261 -0
- package/crates/tish_lsp/src/import_goto.rs +549 -0
- package/crates/tish_lsp/src/main.rs +502 -102
- package/crates/tish_native/src/build.rs +3 -2
- package/crates/tish_native/src/lib.rs +6 -2
- package/crates/tish_opt/src/lib.rs +17 -2
- package/crates/tish_parser/src/lib.rs +10 -3
- package/crates/tish_parser/src/parser.rs +346 -56
- package/crates/tish_resolve/Cargo.toml +13 -0
- package/crates/tish_resolve/src/lib.rs +3436 -0
- package/crates/tish_resolve/src/pos.rs +133 -0
- package/crates/tish_runtime/Cargo.toml +68 -3
- package/crates/tish_runtime/src/http.rs +1123 -141
- package/crates/tish_runtime/src/http_fetch.rs +15 -14
- package/crates/tish_runtime/src/http_hyper.rs +418 -0
- package/crates/tish_runtime/src/http_prefork.rs +189 -0
- package/crates/tish_runtime/src/lib.rs +159 -29
- package/crates/tish_runtime/src/promise.rs +199 -36
- package/crates/tish_runtime/src/promise_io.rs +2 -1
- package/crates/tish_runtime/src/timers.rs +37 -1
- package/crates/tish_runtime/src/ws.rs +26 -28
- package/crates/tish_ui/src/jsx.rs +279 -8
- package/crates/tish_ui/src/lib.rs +5 -2
- package/crates/tish_ui/src/runtime/hooks.rs +406 -45
- package/crates/tish_ui/src/runtime/mod.rs +36 -9
- package/crates/tish_vm/Cargo.toml +15 -5
- package/crates/tish_vm/src/vm.rs +506 -259
- package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +3 -1
- package/crates/tish_wasm/src/lib.rs +17 -14
- package/crates/tish_wasm_runtime/Cargo.toml +2 -1
- package/crates/tish_wasm_runtime/src/lib.rs +1 -1
- package/crates/tishlang_cargo_bindgen/Cargo.toml +1 -0
- package/crates/tishlang_cargo_bindgen/src/discover.rs +68 -0
- package/crates/tishlang_cargo_bindgen/src/lib.rs +5 -4
- package/justfile +8 -0
- package/package.json +1 -1
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- package/platform/win32-x64/tish.exe +0 -0
|
@@ -159,6 +159,8 @@ impl<'a> Parser<'a> {
|
|
|
159
159
|
}
|
|
160
160
|
TokenKind::Import => self.parse_import()?,
|
|
161
161
|
TokenKind::Export => self.parse_export()?,
|
|
162
|
+
TokenKind::Type => self.parse_type_alias()?,
|
|
163
|
+
TokenKind::Declare => self.parse_declare()?,
|
|
162
164
|
_ => {
|
|
163
165
|
let expr = self.parse_expr()?;
|
|
164
166
|
let span_end = expr.span().end;
|
|
@@ -216,11 +218,26 @@ impl<'a> Parser<'a> {
|
|
|
216
218
|
self.advance();
|
|
217
219
|
}
|
|
218
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
|
+
|
|
219
236
|
Ok(Statement::Block {
|
|
220
237
|
statements,
|
|
221
238
|
span: Span {
|
|
222
239
|
start: span_start,
|
|
223
|
-
end
|
|
240
|
+
end,
|
|
224
241
|
},
|
|
225
242
|
})
|
|
226
243
|
}
|
|
@@ -248,8 +265,12 @@ impl<'a> Parser<'a> {
|
|
|
248
265
|
});
|
|
249
266
|
}
|
|
250
267
|
|
|
251
|
-
let
|
|
252
|
-
|
|
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
|
|
253
274
|
.literal
|
|
254
275
|
.clone()
|
|
255
276
|
.ok_or("Expected identifier")?;
|
|
@@ -270,6 +291,7 @@ impl<'a> Parser<'a> {
|
|
|
270
291
|
};
|
|
271
292
|
Ok(Statement::VarDecl {
|
|
272
293
|
name,
|
|
294
|
+
name_span,
|
|
273
295
|
mutable,
|
|
274
296
|
type_ann,
|
|
275
297
|
init,
|
|
@@ -300,12 +322,16 @@ impl<'a> Parser<'a> {
|
|
|
300
322
|
// Rest element: ...rest
|
|
301
323
|
if matches!(self.peek_kind(), Some(TokenKind::Spread)) {
|
|
302
324
|
self.advance();
|
|
303
|
-
let
|
|
304
|
-
|
|
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
|
|
305
331
|
.literal
|
|
306
332
|
.clone()
|
|
307
333
|
.ok_or("Expected identifier")?;
|
|
308
|
-
elements.push(Some(DestructElement::Rest(name)));
|
|
334
|
+
elements.push(Some(DestructElement::Rest(name, name_span)));
|
|
309
335
|
break;
|
|
310
336
|
}
|
|
311
337
|
|
|
@@ -316,13 +342,16 @@ impl<'a> Parser<'a> {
|
|
|
316
342
|
DestructElement::Pattern(Box::new(nested))
|
|
317
343
|
}
|
|
318
344
|
Some(TokenKind::Ident) => {
|
|
319
|
-
let
|
|
320
|
-
|
|
321
|
-
.
|
|
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
|
|
322
351
|
.literal
|
|
323
352
|
.clone()
|
|
324
353
|
.ok_or("Expected identifier")?;
|
|
325
|
-
DestructElement::Ident(name)
|
|
354
|
+
DestructElement::Ident(name, name_span)
|
|
326
355
|
}
|
|
327
356
|
_ => return Err("Expected identifier or pattern in destructuring".to_string()),
|
|
328
357
|
};
|
|
@@ -344,8 +373,12 @@ impl<'a> Parser<'a> {
|
|
|
344
373
|
let mut props = Vec::new();
|
|
345
374
|
|
|
346
375
|
while !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
|
|
347
|
-
let
|
|
348
|
-
|
|
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
|
|
349
382
|
.literal
|
|
350
383
|
.clone()
|
|
351
384
|
.ok_or("Expected identifier")?;
|
|
@@ -359,19 +392,22 @@ impl<'a> Parser<'a> {
|
|
|
359
392
|
DestructElement::Pattern(Box::new(nested))
|
|
360
393
|
}
|
|
361
394
|
Some(TokenKind::Ident) => {
|
|
362
|
-
let
|
|
363
|
-
|
|
364
|
-
.
|
|
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
|
|
365
401
|
.literal
|
|
366
402
|
.clone()
|
|
367
403
|
.ok_or("Expected identifier")?;
|
|
368
|
-
DestructElement::Ident(name)
|
|
404
|
+
DestructElement::Ident(name, name_span)
|
|
369
405
|
}
|
|
370
406
|
_ => return Err("Expected identifier or pattern after ':'".to_string()),
|
|
371
407
|
}
|
|
372
408
|
} else {
|
|
373
409
|
// Shorthand: { key } is equivalent to { key: key }
|
|
374
|
-
DestructElement::Ident(key.clone())
|
|
410
|
+
DestructElement::Ident(key.clone(), key_span)
|
|
375
411
|
};
|
|
376
412
|
|
|
377
413
|
props.push(DestructProp { key, value });
|
|
@@ -412,8 +448,12 @@ impl<'a> Parser<'a> {
|
|
|
412
448
|
default,
|
|
413
449
|
});
|
|
414
450
|
}
|
|
415
|
-
let
|
|
416
|
-
|
|
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
|
|
417
457
|
.literal
|
|
418
458
|
.clone()
|
|
419
459
|
.ok_or("Expected param name")?;
|
|
@@ -431,6 +471,7 @@ impl<'a> Parser<'a> {
|
|
|
431
471
|
};
|
|
432
472
|
Ok(FunParam::Simple(TypedParam {
|
|
433
473
|
name: param_name,
|
|
474
|
+
name_span,
|
|
434
475
|
type_ann,
|
|
435
476
|
default,
|
|
436
477
|
}))
|
|
@@ -468,6 +509,11 @@ impl<'a> Parser<'a> {
|
|
|
468
509
|
let name = tok.literal.clone().ok_or("Expected type name")?;
|
|
469
510
|
Ok(TypeAnnotation::Simple(name))
|
|
470
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
|
+
}
|
|
471
517
|
// Handle keywords that can be type names
|
|
472
518
|
Some(TokenKind::Null) => {
|
|
473
519
|
self.advance();
|
|
@@ -491,8 +537,13 @@ impl<'a> Parser<'a> {
|
|
|
491
537
|
let typ = self.parse_type_annotation()?;
|
|
492
538
|
props.push((key, typ));
|
|
493
539
|
if !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
|
|
494
|
-
//
|
|
495
|
-
|
|
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
|
+
) {
|
|
496
547
|
self.advance();
|
|
497
548
|
}
|
|
498
549
|
}
|
|
@@ -511,9 +562,7 @@ impl<'a> Parser<'a> {
|
|
|
511
562
|
}
|
|
512
563
|
}
|
|
513
564
|
self.expect(TokenKind::RParen)?;
|
|
514
|
-
|
|
515
|
-
self.expect(TokenKind::Assign)?; // =
|
|
516
|
-
self.expect(TokenKind::Gt)?; // > (forms =>)
|
|
565
|
+
self.expect(TokenKind::Arrow)?;
|
|
517
566
|
let returns = self.parse_type_annotation()?;
|
|
518
567
|
Ok(TypeAnnotation::Function {
|
|
519
568
|
params,
|
|
@@ -526,8 +575,12 @@ impl<'a> Parser<'a> {
|
|
|
526
575
|
|
|
527
576
|
fn parse_fun_decl(&mut self, async_: bool) -> Result<Statement, String> {
|
|
528
577
|
let span_start = self.expect(TokenKind::Fn)?.span.start;
|
|
529
|
-
let
|
|
530
|
-
|
|
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
|
|
531
584
|
.literal
|
|
532
585
|
.clone()
|
|
533
586
|
.ok_or("Expected function name")?;
|
|
@@ -537,8 +590,12 @@ impl<'a> Parser<'a> {
|
|
|
537
590
|
while !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
538
591
|
if matches!(self.peek_kind(), Some(TokenKind::Spread)) {
|
|
539
592
|
self.advance();
|
|
540
|
-
let
|
|
541
|
-
|
|
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
|
|
542
599
|
.literal
|
|
543
600
|
.clone()
|
|
544
601
|
.ok_or("Expected rest param name")?;
|
|
@@ -551,6 +608,7 @@ impl<'a> Parser<'a> {
|
|
|
551
608
|
};
|
|
552
609
|
rest_param = Some(TypedParam {
|
|
553
610
|
name: param_name,
|
|
611
|
+
name_span: rest_name_span,
|
|
554
612
|
type_ann,
|
|
555
613
|
default: None,
|
|
556
614
|
});
|
|
@@ -589,13 +647,182 @@ impl<'a> Parser<'a> {
|
|
|
589
647
|
Box::new(self.parse_block()?)
|
|
590
648
|
};
|
|
591
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
|
+
|
|
592
662
|
Ok(Statement::FunDecl {
|
|
593
663
|
async_,
|
|
594
664
|
name,
|
|
665
|
+
name_span,
|
|
595
666
|
params,
|
|
596
667
|
rest_param,
|
|
597
668
|
return_type,
|
|
598
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,
|
|
599
826
|
span: self.span_end(span_start),
|
|
600
827
|
})
|
|
601
828
|
}
|
|
@@ -640,8 +867,12 @@ impl<'a> Parser<'a> {
|
|
|
640
867
|
let mutable = matches!(self.peek_kind(), Some(TokenKind::Let));
|
|
641
868
|
let var_span_start = self.peek().map(|t| t.span.start).unwrap_or((0, 0));
|
|
642
869
|
self.advance();
|
|
643
|
-
let
|
|
644
|
-
|
|
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
|
|
645
876
|
.literal
|
|
646
877
|
.clone()
|
|
647
878
|
.ok_or("Expected identifier")?;
|
|
@@ -652,6 +883,7 @@ impl<'a> Parser<'a> {
|
|
|
652
883
|
let body = Box::new(self.parse_block_or_statement()?);
|
|
653
884
|
return Ok(Statement::ForOf {
|
|
654
885
|
name,
|
|
886
|
+
name_span,
|
|
655
887
|
iterable,
|
|
656
888
|
body,
|
|
657
889
|
span: self.span_end(span_start),
|
|
@@ -674,6 +906,7 @@ impl<'a> Parser<'a> {
|
|
|
674
906
|
}
|
|
675
907
|
Some(Box::new(Statement::VarDecl {
|
|
676
908
|
name,
|
|
909
|
+
name_span,
|
|
677
910
|
mutable,
|
|
678
911
|
type_ann,
|
|
679
912
|
init: init_expr,
|
|
@@ -815,13 +1048,19 @@ impl<'a> Parser<'a> {
|
|
|
815
1048
|
let body = Box::new(self.parse_block_or_statement()?);
|
|
816
1049
|
|
|
817
1050
|
let mut catch_param = None;
|
|
1051
|
+
let mut catch_param_span = None;
|
|
818
1052
|
let mut catch_body = None;
|
|
819
1053
|
let mut finally_body = None;
|
|
820
1054
|
|
|
821
1055
|
if matches!(self.peek_kind(), Some(TokenKind::Catch)) {
|
|
822
1056
|
self.advance();
|
|
823
1057
|
self.expect(TokenKind::LParen)?;
|
|
824
|
-
|
|
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();
|
|
825
1064
|
self.expect(TokenKind::RParen)?;
|
|
826
1065
|
catch_body = Some(Box::new(self.parse_block_or_statement()?));
|
|
827
1066
|
}
|
|
@@ -838,6 +1077,7 @@ impl<'a> Parser<'a> {
|
|
|
838
1077
|
Ok(Statement::Try {
|
|
839
1078
|
body,
|
|
840
1079
|
catch_param,
|
|
1080
|
+
catch_param_span,
|
|
841
1081
|
catch_body,
|
|
842
1082
|
finally_body,
|
|
843
1083
|
span: self.span_end(span_start),
|
|
@@ -851,25 +1091,42 @@ impl<'a> Parser<'a> {
|
|
|
851
1091
|
self.advance();
|
|
852
1092
|
let mut specs = Vec::new();
|
|
853
1093
|
while !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
|
|
854
|
-
let
|
|
855
|
-
|
|
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
|
|
856
1100
|
.literal
|
|
857
1101
|
.clone()
|
|
858
1102
|
.ok_or("Expected identifier in import")?;
|
|
859
|
-
let alias = if matches!(self.peek_kind(), Some(TokenKind::Ident))
|
|
1103
|
+
let (alias, alias_span) = if matches!(self.peek_kind(), Some(TokenKind::Ident))
|
|
860
1104
|
&& self.peek().and_then(|t| t.literal.as_deref()) == Some("as")
|
|
861
1105
|
{
|
|
862
1106
|
self.advance(); // consume 'as'
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
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),
|
|
868
1120
|
)
|
|
869
1121
|
} else {
|
|
870
|
-
None
|
|
1122
|
+
(None, None)
|
|
871
1123
|
};
|
|
872
|
-
specs.push(ImportSpecifier::Named {
|
|
1124
|
+
specs.push(ImportSpecifier::Named {
|
|
1125
|
+
name,
|
|
1126
|
+
name_span,
|
|
1127
|
+
alias,
|
|
1128
|
+
alias_span,
|
|
1129
|
+
});
|
|
873
1130
|
if !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
|
|
874
1131
|
self.expect(TokenKind::Comma)?;
|
|
875
1132
|
}
|
|
@@ -883,20 +1140,31 @@ impl<'a> Parser<'a> {
|
|
|
883
1140
|
if as_tok.literal.as_deref() != Some("as") {
|
|
884
1141
|
return Err("Expected 'as' after '*' in namespace import".to_string());
|
|
885
1142
|
}
|
|
886
|
-
let
|
|
887
|
-
|
|
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
|
|
888
1149
|
.literal
|
|
889
1150
|
.clone()
|
|
890
1151
|
.ok_or("Expected identifier after 'as'")?;
|
|
891
|
-
vec![ImportSpecifier::Namespace
|
|
1152
|
+
vec![ImportSpecifier::Namespace {
|
|
1153
|
+
name: alias,
|
|
1154
|
+
name_span,
|
|
1155
|
+
}]
|
|
892
1156
|
} else if matches!(self.peek_kind(), Some(TokenKind::Ident)) {
|
|
893
1157
|
// Default: import X from "..."
|
|
894
|
-
let
|
|
895
|
-
|
|
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
|
|
896
1164
|
.literal
|
|
897
1165
|
.clone()
|
|
898
1166
|
.ok_or("Expected identifier")?;
|
|
899
|
-
vec![ImportSpecifier::Default
|
|
1167
|
+
vec![ImportSpecifier::Default { name, name_span }]
|
|
900
1168
|
} else {
|
|
901
1169
|
return Err("Expected { }, * as name, or default import".to_string());
|
|
902
1170
|
};
|
|
@@ -922,6 +1190,10 @@ impl<'a> Parser<'a> {
|
|
|
922
1190
|
self.advance();
|
|
923
1191
|
let expr = self.parse_expr()?;
|
|
924
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()?))
|
|
925
1197
|
} else if matches!(self.peek_kind(), Some(TokenKind::Const)) {
|
|
926
1198
|
ExportDeclaration::Named(Box::new(self.parse_var_decl(false)?))
|
|
927
1199
|
} else if matches!(self.peek_kind(), Some(TokenKind::Let)) {
|
|
@@ -935,7 +1207,10 @@ impl<'a> Parser<'a> {
|
|
|
935
1207
|
}
|
|
936
1208
|
ExportDeclaration::Named(Box::new(self.parse_fun_decl(async_)?))
|
|
937
1209
|
} else {
|
|
938
|
-
return Err(
|
|
1210
|
+
return Err(
|
|
1211
|
+
"Expected 'default', 'type', 'declare', 'const', 'let', or 'fn' after export"
|
|
1212
|
+
.to_string(),
|
|
1213
|
+
);
|
|
939
1214
|
};
|
|
940
1215
|
Ok(Statement::Export {
|
|
941
1216
|
declaration: Box::new(declaration),
|
|
@@ -970,7 +1245,7 @@ impl<'a> Parser<'a> {
|
|
|
970
1245
|
// Member assignment: obj.prop = val
|
|
971
1246
|
if let Expr::Member {
|
|
972
1247
|
object,
|
|
973
|
-
prop: MemberProp::Name
|
|
1248
|
+
prop: MemberProp::Name { name: prop_name, .. },
|
|
974
1249
|
..
|
|
975
1250
|
} = &left
|
|
976
1251
|
{
|
|
@@ -1208,16 +1483,23 @@ impl<'a> Parser<'a> {
|
|
|
1208
1483
|
TokenKind::Dot | TokenKind::OptionalChain => {
|
|
1209
1484
|
let optional = kind == TokenKind::OptionalChain;
|
|
1210
1485
|
self.advance();
|
|
1211
|
-
let
|
|
1212
|
-
|
|
1486
|
+
let prop_tok = self.expect(TokenKind::Ident)?;
|
|
1487
|
+
let prop = prop_tok
|
|
1213
1488
|
.literal
|
|
1214
1489
|
.clone()
|
|
1215
1490
|
.ok_or("Expected property name")?;
|
|
1491
|
+
let prop_span = Span {
|
|
1492
|
+
start: prop_tok.span.start,
|
|
1493
|
+
end: prop_tok.span.end,
|
|
1494
|
+
};
|
|
1216
1495
|
let start = expr.span().start;
|
|
1217
1496
|
let end = self.peek().map(|x| x.span.start).unwrap_or(start);
|
|
1218
1497
|
expr = Expr::Member {
|
|
1219
1498
|
object: Box::new(expr),
|
|
1220
|
-
prop: MemberProp::Name
|
|
1499
|
+
prop: MemberProp::Name {
|
|
1500
|
+
name: prop,
|
|
1501
|
+
span: prop_span,
|
|
1502
|
+
},
|
|
1221
1503
|
optional,
|
|
1222
1504
|
span: Span { start, end },
|
|
1223
1505
|
};
|
|
@@ -1321,16 +1603,23 @@ impl<'a> Parser<'a> {
|
|
|
1321
1603
|
TokenKind::Dot | TokenKind::OptionalChain => {
|
|
1322
1604
|
let optional = kind == TokenKind::OptionalChain;
|
|
1323
1605
|
self.advance();
|
|
1324
|
-
let
|
|
1325
|
-
|
|
1606
|
+
let prop_tok = self.expect(TokenKind::Ident)?;
|
|
1607
|
+
let prop = prop_tok
|
|
1326
1608
|
.literal
|
|
1327
1609
|
.clone()
|
|
1328
1610
|
.ok_or("Expected property name")?;
|
|
1611
|
+
let prop_span = Span {
|
|
1612
|
+
start: prop_tok.span.start,
|
|
1613
|
+
end: prop_tok.span.end,
|
|
1614
|
+
};
|
|
1329
1615
|
let start = expr.span().start;
|
|
1330
1616
|
let end = self.peek().map(|x| x.span.start).unwrap_or(start);
|
|
1331
1617
|
expr = Expr::Member {
|
|
1332
1618
|
object: Box::new(expr),
|
|
1333
|
-
prop: MemberProp::Name
|
|
1619
|
+
prop: MemberProp::Name {
|
|
1620
|
+
name: prop,
|
|
1621
|
+
span: prop_span,
|
|
1622
|
+
},
|
|
1334
1623
|
optional,
|
|
1335
1624
|
span: Span { start, end },
|
|
1336
1625
|
};
|
|
@@ -1424,6 +1713,7 @@ impl<'a> Parser<'a> {
|
|
|
1424
1713
|
return Ok(Expr::ArrowFunction {
|
|
1425
1714
|
params: vec![FunParam::Simple(TypedParam {
|
|
1426
1715
|
name: name.clone(),
|
|
1716
|
+
name_span: span,
|
|
1427
1717
|
type_ann: None,
|
|
1428
1718
|
default: None,
|
|
1429
1719
|
})],
|
|
@@ -1491,7 +1781,7 @@ impl<'a> Parser<'a> {
|
|
|
1491
1781
|
} else {
|
|
1492
1782
|
let key_tok = self.advance().ok_or("Expected object key")?;
|
|
1493
1783
|
let (key, key_span, is_ident_key) = match key_tok.kind {
|
|
1494
|
-
TokenKind::Ident => {
|
|
1784
|
+
TokenKind::Ident | TokenKind::Type | TokenKind::Declare => {
|
|
1495
1785
|
let k = key_tok.literal.clone().ok_or("Expected key")?;
|
|
1496
1786
|
let sp = Span {
|
|
1497
1787
|
start: key_tok.span.start,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "tishlang_resolve"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Lexical name resolution for Tish (LSP, tooling)"
|
|
6
|
+
license-file = { workspace = true }
|
|
7
|
+
repository = { workspace = true }
|
|
8
|
+
|
|
9
|
+
[dependencies]
|
|
10
|
+
tishlang_ast = { path = "../tish_ast", version = ">=0.1" }
|
|
11
|
+
|
|
12
|
+
[dev-dependencies]
|
|
13
|
+
tishlang_parser = { path = "../tish_parser", version = ">=0.1" }
|