@tishlang/tish 1.6.0 → 1.7.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/bin/tish +0 -0
- package/crates/js_to_tish/src/error.rs +2 -8
- package/crates/js_to_tish/src/transform/expr.rs +101 -130
- package/crates/js_to_tish/src/transform/stmt.rs +25 -22
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cli_help.rs +76 -29
- package/crates/tish/src/main.rs +85 -54
- package/crates/tish/tests/cargo_example_compile.rs +3 -1
- package/crates/tish/tests/integration_test.rs +197 -47
- package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
- package/crates/tish/tests/shortcircuit.rs +19 -4
- package/crates/tish_ast/src/ast.rs +12 -14
- package/crates/tish_build_utils/src/lib.rs +31 -6
- package/crates/tish_builtins/src/array.rs +52 -21
- package/crates/tish_builtins/src/construct.rs +2 -8
- package/crates/tish_builtins/src/globals.rs +30 -15
- package/crates/tish_builtins/src/lib.rs +5 -5
- package/crates/tish_builtins/src/math.rs +5 -3
- package/crates/tish_builtins/src/string.rs +71 -19
- package/crates/tish_bytecode/src/chunk.rs +0 -1
- package/crates/tish_bytecode/src/compiler.rs +164 -60
- package/crates/tish_bytecode/src/opcode.rs +13 -4
- package/crates/tish_bytecode/src/peephole.rs +2 -2
- package/crates/tish_compile/src/codegen.rs +921 -299
- package/crates/tish_compile/src/infer.rs +69 -19
- package/crates/tish_compile/src/lib.rs +15 -5
- package/crates/tish_compile/src/resolve.rs +112 -69
- package/crates/tish_compile/src/types.rs +10 -14
- package/crates/tish_compile_js/src/codegen.rs +34 -13
- package/crates/tish_compile_js/src/tests_jsx.rs +30 -6
- package/crates/tish_compiler_wasm/src/lib.rs +16 -13
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +39 -48
- package/crates/tish_core/src/json.rs +5 -3
- package/crates/tish_core/src/lib.rs +1 -1
- package/crates/tish_core/src/uri.rs +9 -6
- package/crates/tish_core/src/value.rs +92 -28
- package/crates/tish_cranelift/src/link.rs +6 -9
- package/crates/tish_cranelift/src/lower.rs +14 -8
- package/crates/tish_eval/src/eval.rs +389 -142
- package/crates/tish_eval/src/lib.rs +10 -6
- package/crates/tish_eval/src/natives.rs +95 -38
- package/crates/tish_eval/src/promise.rs +14 -8
- package/crates/tish_eval/src/timers.rs +28 -19
- package/crates/tish_eval/src/value.rs +10 -3
- package/crates/tish_fmt/src/lib.rs +29 -13
- package/crates/tish_lexer/src/lib.rs +217 -63
- package/crates/tish_lexer/src/token.rs +6 -6
- package/crates/tish_llvm/src/lib.rs +15 -8
- package/crates/tish_lsp/src/main.rs +41 -43
- package/crates/tish_native/src/build.rs +1 -6
- package/crates/tish_native/src/lib.rs +48 -19
- package/crates/tish_opt/src/lib.rs +67 -50
- package/crates/tish_parser/src/lib.rs +36 -11
- package/crates/tish_parser/src/parser.rs +172 -87
- package/crates/tish_runtime/src/http.rs +15 -6
- package/crates/tish_runtime/src/http_fetch.rs +24 -14
- package/crates/tish_runtime/src/lib.rs +224 -168
- package/crates/tish_runtime/src/promise.rs +1 -5
- package/crates/tish_runtime/src/ws.rs +45 -20
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
- package/crates/tish_ui/src/jsx.rs +41 -22
- package/crates/tish_ui/src/lib.rs +2 -2
- package/crates/tish_vm/src/vm.rs +309 -112
- package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +8 -3
- package/crates/tish_wasm/src/lib.rs +38 -28
- package/crates/tishlang_cargo_bindgen/Cargo.toml +25 -0
- package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
- package/crates/tishlang_cargo_bindgen/src/discover.rs +52 -0
- package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
- package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
- package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -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
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
mod token;
|
|
7
7
|
|
|
8
|
-
pub use token::{Token, TokenKind
|
|
8
|
+
pub use token::{Span, Token, TokenKind};
|
|
9
9
|
|
|
10
10
|
use std::collections::VecDeque;
|
|
11
11
|
use std::iter::Peekable;
|
|
@@ -74,14 +74,21 @@ impl<'a> Lexer<'a> {
|
|
|
74
74
|
loop {
|
|
75
75
|
match self.peek() {
|
|
76
76
|
None | Some('{') | Some('<') => break,
|
|
77
|
-
Some(c) => {
|
|
77
|
+
Some(c) => {
|
|
78
|
+
self.advance();
|
|
79
|
+
s.push(c);
|
|
80
|
+
}
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
if s.is_empty() {
|
|
81
84
|
Ok(None)
|
|
82
85
|
} else {
|
|
83
86
|
let end = self.span_start();
|
|
84
|
-
Ok(Some(Token {
|
|
87
|
+
Ok(Some(Token {
|
|
88
|
+
kind: TokenKind::JsxText,
|
|
89
|
+
span: Span { start, end },
|
|
90
|
+
literal: Some(s.into()),
|
|
91
|
+
}))
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
|
|
@@ -139,7 +146,9 @@ impl<'a> Lexer<'a> {
|
|
|
139
146
|
|
|
140
147
|
fn skip_line_comment(&mut self) {
|
|
141
148
|
while let Some(c) = self.advance() {
|
|
142
|
-
if c == '\n' {
|
|
149
|
+
if c == '\n' {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
143
152
|
}
|
|
144
153
|
}
|
|
145
154
|
|
|
@@ -147,8 +156,14 @@ impl<'a> Lexer<'a> {
|
|
|
147
156
|
let mut depth = 1;
|
|
148
157
|
while depth > 0 {
|
|
149
158
|
match self.advance() {
|
|
150
|
-
Some('*') if self.peek() == Some('/') => {
|
|
151
|
-
|
|
159
|
+
Some('*') if self.peek() == Some('/') => {
|
|
160
|
+
self.advance();
|
|
161
|
+
depth -= 1;
|
|
162
|
+
}
|
|
163
|
+
Some('/') if self.peek() == Some('*') => {
|
|
164
|
+
self.advance();
|
|
165
|
+
depth += 1;
|
|
166
|
+
}
|
|
152
167
|
None => return Err("Unterminated block comment".to_string()),
|
|
153
168
|
_ => {}
|
|
154
169
|
}
|
|
@@ -186,7 +201,11 @@ impl<'a> Lexer<'a> {
|
|
|
186
201
|
|
|
187
202
|
fn read_string(&mut self, quote: char) -> Result<String, String> {
|
|
188
203
|
let mut s = String::with_capacity(32);
|
|
189
|
-
let extra = if quote == '"' {
|
|
204
|
+
let extra = if quote == '"' {
|
|
205
|
+
&['"', '\''][..]
|
|
206
|
+
} else {
|
|
207
|
+
&['\'', '"'][..]
|
|
208
|
+
};
|
|
190
209
|
loop {
|
|
191
210
|
match self.advance() {
|
|
192
211
|
None => return Err("Unterminated string".to_string()),
|
|
@@ -213,24 +232,44 @@ impl<'a> Lexer<'a> {
|
|
|
213
232
|
}
|
|
214
233
|
|
|
215
234
|
/// Read a template literal. If `is_continuation` is true, we're continuing after a `}`.
|
|
216
|
-
fn read_template(
|
|
235
|
+
fn read_template(
|
|
236
|
+
&mut self,
|
|
237
|
+
start: (usize, usize),
|
|
238
|
+
is_continuation: bool,
|
|
239
|
+
) -> Result<Option<Token>, String> {
|
|
217
240
|
let mut s = String::with_capacity(if is_continuation { 32 } else { 64 });
|
|
218
241
|
let extra = &['`', '$', '{'][..];
|
|
219
|
-
|
|
242
|
+
|
|
220
243
|
loop {
|
|
221
244
|
match self.advance() {
|
|
222
245
|
None => return Err("Unterminated template literal".to_string()),
|
|
223
246
|
Some('`') => {
|
|
224
247
|
let end = self.span_start();
|
|
225
|
-
let kind = if is_continuation {
|
|
226
|
-
|
|
248
|
+
let kind = if is_continuation {
|
|
249
|
+
TokenKind::TemplateTail
|
|
250
|
+
} else {
|
|
251
|
+
TokenKind::TemplateNoSub
|
|
252
|
+
};
|
|
253
|
+
return Ok(Some(Token {
|
|
254
|
+
kind,
|
|
255
|
+
span: Span { start, end },
|
|
256
|
+
literal: Some(s.into()),
|
|
257
|
+
}));
|
|
227
258
|
}
|
|
228
259
|
Some('$') if self.peek() == Some('{') => {
|
|
229
260
|
self.advance();
|
|
230
261
|
self.template_brace_stack.push(1);
|
|
231
262
|
let end = self.span_start();
|
|
232
|
-
let kind = if is_continuation {
|
|
233
|
-
|
|
263
|
+
let kind = if is_continuation {
|
|
264
|
+
TokenKind::TemplateMiddle
|
|
265
|
+
} else {
|
|
266
|
+
TokenKind::TemplateHead
|
|
267
|
+
};
|
|
268
|
+
return Ok(Some(Token {
|
|
269
|
+
kind,
|
|
270
|
+
span: Span { start, end },
|
|
271
|
+
literal: Some(s.into()),
|
|
272
|
+
}));
|
|
234
273
|
}
|
|
235
274
|
Some('\\') => s.push(self.handle_escape(extra)?),
|
|
236
275
|
Some(c) => s.push(c),
|
|
@@ -308,7 +347,10 @@ impl<'a> Lexer<'a> {
|
|
|
308
347
|
self.indent_stack.pop();
|
|
309
348
|
return Ok(Some(Token {
|
|
310
349
|
kind: TokenKind::Dedent,
|
|
311
|
-
span: Span {
|
|
350
|
+
span: Span {
|
|
351
|
+
start: (self.line, self.col),
|
|
352
|
+
end: (self.line, self.col),
|
|
353
|
+
},
|
|
312
354
|
literal: None,
|
|
313
355
|
}));
|
|
314
356
|
}
|
|
@@ -362,31 +404,66 @@ impl<'a> Lexer<'a> {
|
|
|
362
404
|
';' => TokenKind::Semicolon,
|
|
363
405
|
',' => TokenKind::Comma,
|
|
364
406
|
'.' => {
|
|
365
|
-
if self.peek() == Some('?') {
|
|
366
|
-
else if self.peek() == Some('.') {
|
|
407
|
+
if self.peek() == Some('?') {
|
|
367
408
|
self.advance();
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
409
|
+
TokenKind::OptionalChain
|
|
410
|
+
} else if self.peek() == Some('.') {
|
|
411
|
+
self.advance();
|
|
412
|
+
if self.peek() == Some('.') {
|
|
413
|
+
self.advance();
|
|
414
|
+
TokenKind::Spread
|
|
415
|
+
} else {
|
|
416
|
+
return Err("Unexpected .. (use ... for rest params)".to_string());
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
TokenKind::Dot
|
|
420
|
+
}
|
|
371
421
|
}
|
|
372
422
|
'=' => {
|
|
373
423
|
if self.peek() == Some('=') {
|
|
374
424
|
self.advance();
|
|
375
|
-
if self.peek() == Some('=') {
|
|
376
|
-
|
|
377
|
-
|
|
425
|
+
if self.peek() == Some('=') {
|
|
426
|
+
self.advance();
|
|
427
|
+
TokenKind::StrictEq
|
|
428
|
+
} else {
|
|
429
|
+
TokenKind::Eq
|
|
430
|
+
}
|
|
431
|
+
} else if self.peek() == Some('>') {
|
|
432
|
+
self.advance();
|
|
433
|
+
TokenKind::Arrow
|
|
434
|
+
} else {
|
|
435
|
+
TokenKind::Assign
|
|
436
|
+
}
|
|
378
437
|
}
|
|
379
438
|
'!' => {
|
|
380
439
|
if self.peek() == Some('=') {
|
|
381
440
|
self.advance();
|
|
382
|
-
if self.peek() == Some('=') {
|
|
383
|
-
|
|
441
|
+
if self.peek() == Some('=') {
|
|
442
|
+
self.advance();
|
|
443
|
+
TokenKind::StrictNe
|
|
444
|
+
} else {
|
|
445
|
+
TokenKind::Ne
|
|
446
|
+
}
|
|
447
|
+
} else {
|
|
448
|
+
TokenKind::Not
|
|
449
|
+
}
|
|
384
450
|
}
|
|
385
451
|
'<' => {
|
|
386
|
-
if self.peek() == Some('=') {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
else if self.peek() == Some('
|
|
452
|
+
if self.peek() == Some('=') {
|
|
453
|
+
self.advance();
|
|
454
|
+
TokenKind::Le
|
|
455
|
+
} else if self.peek() == Some('<') {
|
|
456
|
+
self.advance();
|
|
457
|
+
TokenKind::Shl
|
|
458
|
+
} else if self.peek() == Some('/') {
|
|
459
|
+
self.jsx_in_closing_tag = true;
|
|
460
|
+
TokenKind::Lt
|
|
461
|
+
} else if self.peek() == Some('>')
|
|
462
|
+
|| self
|
|
463
|
+
.peek()
|
|
464
|
+
.map(|c| c.is_ascii_alphabetic() || c == '_')
|
|
465
|
+
.unwrap_or(false)
|
|
466
|
+
{
|
|
390
467
|
self.jsx_depth += 1;
|
|
391
468
|
self.jsx_stack.push(JsxEl {
|
|
392
469
|
in_opener: true,
|
|
@@ -394,12 +471,18 @@ impl<'a> Lexer<'a> {
|
|
|
394
471
|
});
|
|
395
472
|
self.jsx_in_opening_tag = true;
|
|
396
473
|
TokenKind::Lt
|
|
397
|
-
} else {
|
|
474
|
+
} else {
|
|
475
|
+
TokenKind::Lt
|
|
476
|
+
}
|
|
398
477
|
}
|
|
399
478
|
'>' => {
|
|
400
|
-
if self.peek() == Some('=') {
|
|
401
|
-
|
|
402
|
-
|
|
479
|
+
if self.peek() == Some('=') {
|
|
480
|
+
self.advance();
|
|
481
|
+
TokenKind::Ge
|
|
482
|
+
} else if self.peek() == Some('>') {
|
|
483
|
+
self.advance();
|
|
484
|
+
TokenKind::Shr
|
|
485
|
+
} else {
|
|
403
486
|
if self.jsx_in_closing_tag {
|
|
404
487
|
self.jsx_depth = (self.jsx_depth - 1).max(0);
|
|
405
488
|
self.jsx_stack.pop();
|
|
@@ -425,66 +508,126 @@ impl<'a> Lexer<'a> {
|
|
|
425
508
|
'^' => TokenKind::BitXor,
|
|
426
509
|
'~' => TokenKind::BitNot,
|
|
427
510
|
'+' => {
|
|
428
|
-
if self.peek() == Some('+') {
|
|
429
|
-
|
|
430
|
-
|
|
511
|
+
if self.peek() == Some('+') {
|
|
512
|
+
self.advance();
|
|
513
|
+
TokenKind::PlusPlus
|
|
514
|
+
} else if self.peek() == Some('=') {
|
|
515
|
+
self.advance();
|
|
516
|
+
TokenKind::PlusAssign
|
|
517
|
+
} else {
|
|
518
|
+
TokenKind::Plus
|
|
519
|
+
}
|
|
431
520
|
}
|
|
432
521
|
'-' => {
|
|
433
|
-
if self.peek() == Some('-') {
|
|
434
|
-
|
|
435
|
-
|
|
522
|
+
if self.peek() == Some('-') {
|
|
523
|
+
self.advance();
|
|
524
|
+
TokenKind::MinusMinus
|
|
525
|
+
} else if self.peek() == Some('=') {
|
|
526
|
+
self.advance();
|
|
527
|
+
TokenKind::MinusAssign
|
|
528
|
+
} else {
|
|
529
|
+
TokenKind::Minus
|
|
530
|
+
}
|
|
436
531
|
}
|
|
437
532
|
'*' => {
|
|
438
|
-
if self.peek() == Some('*') {
|
|
439
|
-
|
|
440
|
-
|
|
533
|
+
if self.peek() == Some('*') {
|
|
534
|
+
self.advance();
|
|
535
|
+
TokenKind::StarStar
|
|
536
|
+
} else if self.peek() == Some('=') {
|
|
537
|
+
self.advance();
|
|
538
|
+
TokenKind::StarAssign
|
|
539
|
+
} else {
|
|
540
|
+
TokenKind::Star
|
|
541
|
+
}
|
|
441
542
|
}
|
|
442
543
|
'/' => {
|
|
443
|
-
if self.peek() == Some('/') {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
544
|
+
if self.peek() == Some('/') {
|
|
545
|
+
self.advance();
|
|
546
|
+
self.skip_line_comment();
|
|
547
|
+
return self.next_token();
|
|
548
|
+
} else if self.peek() == Some('*') {
|
|
549
|
+
self.advance();
|
|
550
|
+
self.skip_block_comment()?;
|
|
551
|
+
return self.next_token();
|
|
552
|
+
} else if self.peek() == Some('=') {
|
|
553
|
+
self.advance();
|
|
554
|
+
TokenKind::SlashAssign
|
|
555
|
+
} else {
|
|
556
|
+
if self.jsx_in_opening_tag {
|
|
557
|
+
self.jsx_saw_slash_before_gt = true;
|
|
558
|
+
}
|
|
448
559
|
TokenKind::Slash
|
|
449
560
|
}
|
|
450
561
|
}
|
|
451
562
|
'%' => {
|
|
452
|
-
if self.peek() == Some('=') {
|
|
453
|
-
|
|
563
|
+
if self.peek() == Some('=') {
|
|
564
|
+
self.advance();
|
|
565
|
+
TokenKind::PercentAssign
|
|
566
|
+
} else {
|
|
567
|
+
TokenKind::Percent
|
|
568
|
+
}
|
|
454
569
|
}
|
|
455
570
|
'&' => {
|
|
456
571
|
if self.peek() == Some('&') {
|
|
457
572
|
self.advance();
|
|
458
|
-
if self.peek() == Some('=') {
|
|
459
|
-
|
|
460
|
-
|
|
573
|
+
if self.peek() == Some('=') {
|
|
574
|
+
self.advance();
|
|
575
|
+
TokenKind::AndAndAssign
|
|
576
|
+
} else {
|
|
577
|
+
TokenKind::And
|
|
578
|
+
}
|
|
579
|
+
} else {
|
|
580
|
+
TokenKind::BitAnd
|
|
581
|
+
}
|
|
461
582
|
}
|
|
462
583
|
'|' => {
|
|
463
584
|
if self.peek() == Some('|') {
|
|
464
585
|
self.advance();
|
|
465
|
-
if self.peek() == Some('=') {
|
|
466
|
-
|
|
467
|
-
|
|
586
|
+
if self.peek() == Some('=') {
|
|
587
|
+
self.advance();
|
|
588
|
+
TokenKind::OrOrAssign
|
|
589
|
+
} else {
|
|
590
|
+
TokenKind::Or
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
TokenKind::BitOr
|
|
594
|
+
}
|
|
468
595
|
}
|
|
469
596
|
'?' => {
|
|
470
597
|
if self.peek() == Some('?') {
|
|
471
598
|
self.advance();
|
|
472
|
-
if self.peek() == Some('=') {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
599
|
+
if self.peek() == Some('=') {
|
|
600
|
+
self.advance();
|
|
601
|
+
TokenKind::NullishAssign
|
|
602
|
+
} else {
|
|
603
|
+
TokenKind::NullishCoalesce
|
|
604
|
+
}
|
|
605
|
+
} else if self.peek() == Some('.') {
|
|
606
|
+
self.advance();
|
|
607
|
+
TokenKind::OptionalChain
|
|
608
|
+
} else {
|
|
609
|
+
TokenKind::Question
|
|
610
|
+
}
|
|
476
611
|
}
|
|
477
612
|
':' => TokenKind::Colon,
|
|
478
613
|
'"' | '\'' => {
|
|
479
614
|
let s = self.read_string(c)?;
|
|
480
615
|
let end = self.span_start();
|
|
481
|
-
return Ok(Some(Token {
|
|
616
|
+
return Ok(Some(Token {
|
|
617
|
+
kind: TokenKind::String,
|
|
618
|
+
span: Span { start, end },
|
|
619
|
+
literal: Some(s.into()),
|
|
620
|
+
}));
|
|
482
621
|
}
|
|
483
622
|
'`' => return self.read_template(start, false),
|
|
484
623
|
'0'..='9' => {
|
|
485
624
|
let num = self.read_number(c);
|
|
486
625
|
let end = self.span_start();
|
|
487
|
-
return Ok(Some(Token {
|
|
626
|
+
return Ok(Some(Token {
|
|
627
|
+
kind: TokenKind::Number,
|
|
628
|
+
span: Span { start, end },
|
|
629
|
+
literal: Some(num.into()),
|
|
630
|
+
}));
|
|
488
631
|
}
|
|
489
632
|
'a'..='z' | 'A'..='Z' | '_' => {
|
|
490
633
|
let ident = self.read_ident_or_keyword(c);
|
|
@@ -493,15 +636,26 @@ impl<'a> Lexer<'a> {
|
|
|
493
636
|
return Ok(Some(Token {
|
|
494
637
|
kind,
|
|
495
638
|
span: Span { start, end },
|
|
496
|
-
literal: if matches!(kind, TokenKind::Ident) {
|
|
639
|
+
literal: if matches!(kind, TokenKind::Ident) {
|
|
640
|
+
Some(ident.into())
|
|
641
|
+
} else {
|
|
642
|
+
None
|
|
643
|
+
},
|
|
497
644
|
}));
|
|
498
645
|
}
|
|
499
|
-
'\n' => {
|
|
646
|
+
'\n' => {
|
|
647
|
+
self.at_line_start = true;
|
|
648
|
+
return self.next_token();
|
|
649
|
+
}
|
|
500
650
|
_ => return Err(format!("Unexpected character: {:?}", c)),
|
|
501
651
|
};
|
|
502
652
|
|
|
503
653
|
let end = self.span_start();
|
|
504
|
-
Ok(Some(Token {
|
|
654
|
+
Ok(Some(Token {
|
|
655
|
+
kind,
|
|
656
|
+
span: Span { start, end },
|
|
657
|
+
literal: None,
|
|
658
|
+
}))
|
|
505
659
|
}
|
|
506
660
|
}
|
|
507
661
|
|
|
@@ -110,14 +110,14 @@ pub enum TokenKind {
|
|
|
110
110
|
NullishCoalesce,
|
|
111
111
|
Question,
|
|
112
112
|
Arrow,
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
// Template literal tokens
|
|
115
|
-
TemplateNoSub,
|
|
116
|
-
TemplateHead,
|
|
117
|
-
TemplateMiddle,
|
|
118
|
-
TemplateTail,
|
|
115
|
+
TemplateNoSub, // `text` (no interpolation)
|
|
116
|
+
TemplateHead, // `text${ (start with interpolation)
|
|
117
|
+
TemplateMiddle, // }text${ (middle part)
|
|
118
|
+
TemplateTail, // }text` (end part)
|
|
119
119
|
|
|
120
|
-
JsxText,
|
|
120
|
+
JsxText, // Raw text in JSX children (emojis, etc.); only {}<> are special
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
impl TokenKind {
|
|
@@ -17,10 +17,15 @@ pub fn compile_to_native(
|
|
|
17
17
|
project_root: Option<&Path>,
|
|
18
18
|
output_path: &Path,
|
|
19
19
|
) -> Result<(), LlvmError> {
|
|
20
|
-
let modules = resolve_project(entry_path, project_root)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
let modules = resolve_project(entry_path, project_root).map_err(|e| LlvmError {
|
|
21
|
+
message: e.to_string(),
|
|
22
|
+
})?;
|
|
23
|
+
detect_cycles(&modules).map_err(|e| LlvmError {
|
|
24
|
+
message: e.to_string(),
|
|
25
|
+
})?;
|
|
26
|
+
let program = merge_modules(modules).map_err(|e| LlvmError {
|
|
27
|
+
message: e.to_string(),
|
|
28
|
+
})?;
|
|
24
29
|
let chunk = tishlang_bytecode::compile(&program).map_err(|e| LlvmError {
|
|
25
30
|
message: e.to_string(),
|
|
26
31
|
})?;
|
|
@@ -71,7 +76,10 @@ const uint64_t tish_chunk_len = sizeof(tish_chunk_data);
|
|
|
71
76
|
.arg(&chunk_c_path)
|
|
72
77
|
.status()
|
|
73
78
|
.map_err(|e| LlvmError {
|
|
74
|
-
message: format!(
|
|
79
|
+
message: format!(
|
|
80
|
+
"Failed to run clang: {}. Install clang (LLVM) or set CLANG env var.",
|
|
81
|
+
e
|
|
82
|
+
),
|
|
75
83
|
})?;
|
|
76
84
|
|
|
77
85
|
if !status.success() {
|
|
@@ -84,9 +92,8 @@ const uint64_t tish_chunk_len = sizeof(tish_chunk_data);
|
|
|
84
92
|
let object_path_canonical = object_path.canonicalize().map_err(|e| LlvmError {
|
|
85
93
|
message: format!("Cannot canonicalize object path: {}", e),
|
|
86
94
|
})?;
|
|
87
|
-
tishlang_cranelift::link_to_binary(&object_path_canonical, output_path, features)
|
|
88
|
-
message: e.message
|
|
89
|
-
})?;
|
|
95
|
+
tishlang_cranelift::link_to_binary(&object_path_canonical, output_path, features)
|
|
96
|
+
.map_err(|e| LlvmError { message: e.message })?;
|
|
90
97
|
|
|
91
98
|
Ok(())
|
|
92
99
|
}
|
|
@@ -7,12 +7,12 @@ use std::sync::{Arc, RwLock};
|
|
|
7
7
|
use regex::Regex;
|
|
8
8
|
use tower_lsp::jsonrpc::Result;
|
|
9
9
|
use tower_lsp::lsp_types::{
|
|
10
|
-
CompletionItem, CompletionItemKind,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
CompletionItem, CompletionItemKind, CompletionParams, CompletionResponse,
|
|
11
|
+
CompletionTriggerKind, Diagnostic, DiagnosticSeverity, DidChangeTextDocumentParams,
|
|
12
|
+
DidCloseTextDocumentParams, DidOpenTextDocumentParams, DocumentFormattingParams,
|
|
13
|
+
DocumentSymbolParams, DocumentSymbolResponse, GotoDefinitionParams, GotoDefinitionResponse,
|
|
14
|
+
InitializeParams, InitializeResult, Location, MessageType, NumberOrString, OneOf, Position,
|
|
15
|
+
Range, ServerCapabilities, ServerInfo, SymbolInformation, SymbolKind,
|
|
16
16
|
TextDocumentPositionParams, TextDocumentSyncCapability, TextDocumentSyncKind, Url,
|
|
17
17
|
WorkspaceSymbolParams,
|
|
18
18
|
};
|
|
@@ -171,11 +171,7 @@ impl LanguageServer for Backend {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
|
|
174
|
-
let uri = params
|
|
175
|
-
.text_document_position
|
|
176
|
-
.text_document
|
|
177
|
-
.uri
|
|
178
|
-
.clone();
|
|
174
|
+
let uri = params.text_document_position.text_document.uri.clone();
|
|
179
175
|
let _pos = params.text_document_position.position;
|
|
180
176
|
let text = {
|
|
181
177
|
let g = self.docs.read().unwrap();
|
|
@@ -223,10 +219,8 @@ impl LanguageServer for Backend {
|
|
|
223
219
|
}
|
|
224
220
|
|
|
225
221
|
if let Some(ctx) = params.context {
|
|
226
|
-
if matches!(
|
|
227
|
-
ctx.
|
|
228
|
-
CompletionTriggerKind::TRIGGER_CHARACTER
|
|
229
|
-
) && ctx.trigger_character.as_deref() == Some(".")
|
|
222
|
+
if matches!(ctx.trigger_kind, CompletionTriggerKind::TRIGGER_CHARACTER)
|
|
223
|
+
&& ctx.trigger_character.as_deref() == Some(".")
|
|
230
224
|
{
|
|
231
225
|
// After dot: could add member completion later
|
|
232
226
|
}
|
|
@@ -294,16 +288,15 @@ impl LanguageServer for Backend {
|
|
|
294
288
|
if let Some(ref base) = path {
|
|
295
289
|
for s in &program.statements {
|
|
296
290
|
if let tishlang_ast::Statement::Import {
|
|
297
|
-
specifiers,
|
|
298
|
-
from,
|
|
299
|
-
..
|
|
291
|
+
specifiers, from, ..
|
|
300
292
|
} = s
|
|
301
293
|
{
|
|
302
294
|
for sp in specifiers {
|
|
303
295
|
let (imported, local) = match sp {
|
|
304
|
-
tishlang_ast::ImportSpecifier::Named { name, alias } =>
|
|
305
|
-
|
|
306
|
-
|
|
296
|
+
tishlang_ast::ImportSpecifier::Named { name, alias } => (
|
|
297
|
+
name.as_ref(),
|
|
298
|
+
alias.as_ref().map(|a| a.as_ref()).unwrap_or(name.as_ref()),
|
|
299
|
+
),
|
|
307
300
|
tishlang_ast::ImportSpecifier::Default(n) => (n.as_ref(), n.as_ref()),
|
|
308
301
|
_ => continue,
|
|
309
302
|
};
|
|
@@ -325,9 +318,7 @@ impl LanguageServer for Backend {
|
|
|
325
318
|
if let Ok(u) = Url::from_file_path(&can) {
|
|
326
319
|
if let Ok(src) = std::fs::read_to_string(&can) {
|
|
327
320
|
if let Ok(prog) = tishlang_parser::parse(&src) {
|
|
328
|
-
if let Some(loc) =
|
|
329
|
-
find_export(&prog, imported, &u, &src)
|
|
330
|
-
{
|
|
321
|
+
if let Some(loc) = find_export(&prog, imported, &u, &src) {
|
|
331
322
|
return Ok(Some(GotoDefinitionResponse::Scalar(loc)));
|
|
332
323
|
}
|
|
333
324
|
}
|
|
@@ -342,7 +333,10 @@ impl LanguageServer for Backend {
|
|
|
342
333
|
Ok(None)
|
|
343
334
|
}
|
|
344
335
|
|
|
345
|
-
async fn formatting(
|
|
336
|
+
async fn formatting(
|
|
337
|
+
&self,
|
|
338
|
+
params: DocumentFormattingParams,
|
|
339
|
+
) -> Result<Option<Vec<tower_lsp::lsp_types::TextEdit>>> {
|
|
346
340
|
let uri = params.text_document.uri;
|
|
347
341
|
let text = {
|
|
348
342
|
let g = self.docs.read().unwrap();
|
|
@@ -365,10 +359,7 @@ impl LanguageServer for Backend {
|
|
|
365
359
|
}
|
|
366
360
|
Err(e) => {
|
|
367
361
|
self.client
|
|
368
|
-
.show_message(
|
|
369
|
-
MessageType::ERROR,
|
|
370
|
-
format!("tish-fmt (formatter): {}", e),
|
|
371
|
-
)
|
|
362
|
+
.show_message(MessageType::ERROR, format!("tish-fmt (formatter): {}", e))
|
|
372
363
|
.await;
|
|
373
364
|
Ok(None)
|
|
374
365
|
}
|
|
@@ -499,14 +490,18 @@ fn find_decl_in_stmt(
|
|
|
499
490
|
text: &str,
|
|
500
491
|
) -> Option<Location> {
|
|
501
492
|
match s {
|
|
502
|
-
tishlang_ast::Statement::FunDecl { name, span, .. } if name.as_ref() == word =>
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
493
|
+
tishlang_ast::Statement::FunDecl { name, span, .. } if name.as_ref() == word => {
|
|
494
|
+
Some(Location {
|
|
495
|
+
uri: uri.clone(),
|
|
496
|
+
range: span_to_range(span, text),
|
|
497
|
+
})
|
|
498
|
+
}
|
|
499
|
+
tishlang_ast::Statement::VarDecl { name, span, .. } if name.as_ref() == word => {
|
|
500
|
+
Some(Location {
|
|
501
|
+
uri: uri.clone(),
|
|
502
|
+
range: span_to_range(span, text),
|
|
503
|
+
})
|
|
504
|
+
}
|
|
510
505
|
tishlang_ast::Statement::Block { statements, .. } => {
|
|
511
506
|
for x in statements {
|
|
512
507
|
if let Some(l) = find_decl_in_stmt(x, word, uri, text) {
|
|
@@ -521,8 +516,14 @@ fn find_decl_in_stmt(
|
|
|
521
516
|
|
|
522
517
|
fn span_to_range(span: &tishlang_ast::Span, _text: &str) -> Range {
|
|
523
518
|
Range {
|
|
524
|
-
start: pos(
|
|
525
|
-
|
|
519
|
+
start: pos(
|
|
520
|
+
span.start.0.saturating_sub(1) as u32,
|
|
521
|
+
span.start.1.saturating_sub(1) as u32,
|
|
522
|
+
),
|
|
523
|
+
end: pos(
|
|
524
|
+
span.end.0.saturating_sub(1) as u32,
|
|
525
|
+
span.end.1.saturating_sub(1) as u32,
|
|
526
|
+
),
|
|
526
527
|
}
|
|
527
528
|
}
|
|
528
529
|
|
|
@@ -556,10 +557,7 @@ fn doc_symbol_stmt(
|
|
|
556
557
|
) {
|
|
557
558
|
match s {
|
|
558
559
|
tishlang_ast::Statement::FunDecl {
|
|
559
|
-
name,
|
|
560
|
-
span,
|
|
561
|
-
body,
|
|
562
|
-
..
|
|
560
|
+
name, span, body, ..
|
|
563
561
|
} => {
|
|
564
562
|
let mut children = Vec::new();
|
|
565
563
|
collect_child_syms(body, text, &mut children);
|
|
@@ -127,11 +127,7 @@ lto = "thin"
|
|
|
127
127
|
[dependencies]
|
|
128
128
|
tishlang_runtime = {{ path = {:?}{} }}
|
|
129
129
|
{}{}"#,
|
|
130
|
-
out_name,
|
|
131
|
-
runtime_path,
|
|
132
|
-
features_str,
|
|
133
|
-
more_deps,
|
|
134
|
-
ui_dep
|
|
130
|
+
out_name, runtime_path, features_str, more_deps, ui_dep
|
|
135
131
|
);
|
|
136
132
|
|
|
137
133
|
fs::write(build_dir.join("Cargo.toml"), cargo_toml)
|
|
@@ -182,4 +178,3 @@ mod tests {
|
|
|
182
178
|
assert_eq!(f.len(), 5);
|
|
183
179
|
}
|
|
184
180
|
}
|
|
185
|
-
|