@tishlang/tish 1.5.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 +67 -0
- package/crates/tish/tests/fixtures/cargo_example_project/Cargo.toml +3 -0
- package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/Cargo.toml +11 -0
- package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/src/lib.rs +12 -0
- package/crates/tish/tests/fixtures/cargo_example_project/package.json +10 -0
- package/crates/tish/tests/fixtures/cargo_example_project/src/main.tish +3 -0
- 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 +64 -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/Cargo.toml +1 -0
- package/crates/tish_compile/src/codegen.rs +989 -318
- package/crates/tish_compile/src/infer.rs +69 -19
- package/crates/tish_compile/src/lib.rs +21 -8
- package/crates/tish_compile/src/resolve.rs +515 -94
- 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 +40 -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 +398 -141
- 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 +38 -15
- package/crates/tish_native/src/lib.rs +76 -32
- 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 +320 -116
- 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
|
@@ -4,9 +4,9 @@ use std::collections::HashMap;
|
|
|
4
4
|
use std::sync::Arc;
|
|
5
5
|
|
|
6
6
|
use tishlang_ast::{
|
|
7
|
-
ArrayElement, ArrowBody, BinOp, CallArg, DestructElement, DestructPattern,
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
ArrayElement, ArrowBody, BinOp, CallArg, DestructElement, DestructPattern, ExportDeclaration,
|
|
8
|
+
Expr, FunParam, JsxAttrValue, JsxChild, JsxProp, Literal, LogicalAssignOp, MemberProp,
|
|
9
|
+
ObjectProp, Program, Span, Statement,
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
use crate::chunk::{Chunk, Constant};
|
|
@@ -120,9 +120,7 @@ impl<'a> Compiler<'a> {
|
|
|
120
120
|
slots.push(None);
|
|
121
121
|
}
|
|
122
122
|
FunParam::Destructure {
|
|
123
|
-
pattern,
|
|
124
|
-
default,
|
|
125
|
-
..
|
|
123
|
+
pattern, default, ..
|
|
126
124
|
} => {
|
|
127
125
|
if default.is_some() {
|
|
128
126
|
return Err(CompileError {
|
|
@@ -274,8 +272,18 @@ impl<'a> Compiler<'a> {
|
|
|
274
272
|
..
|
|
275
273
|
} = body_expr
|
|
276
274
|
{
|
|
277
|
-
if let (
|
|
278
|
-
|
|
275
|
+
if let (
|
|
276
|
+
Expr::Member {
|
|
277
|
+
object: lo,
|
|
278
|
+
prop: MemberProp::Name(p),
|
|
279
|
+
..
|
|
280
|
+
},
|
|
281
|
+
Expr::Member {
|
|
282
|
+
object: ro,
|
|
283
|
+
prop: MemberProp::Name(pr),
|
|
284
|
+
..
|
|
285
|
+
},
|
|
286
|
+
) = (left.as_ref(), right.as_ref())
|
|
279
287
|
{
|
|
280
288
|
if p != pr {
|
|
281
289
|
return None;
|
|
@@ -327,8 +335,14 @@ impl<'a> Compiler<'a> {
|
|
|
327
335
|
..
|
|
328
336
|
} = body_expr
|
|
329
337
|
{
|
|
330
|
-
if let (
|
|
331
|
-
|
|
338
|
+
if let (
|
|
339
|
+
Expr::Ident {
|
|
340
|
+
name: left_name, ..
|
|
341
|
+
},
|
|
342
|
+
Expr::Ident {
|
|
343
|
+
name: right_name, ..
|
|
344
|
+
},
|
|
345
|
+
) = (left.as_ref(), right.as_ref())
|
|
332
346
|
{
|
|
333
347
|
if left_name.as_ref() == param_a && right_name.as_ref() == param_b {
|
|
334
348
|
return Some(true);
|
|
@@ -360,7 +374,10 @@ impl<'a> Compiler<'a> {
|
|
|
360
374
|
ArrowBody::Expr(e) => e.as_ref(),
|
|
361
375
|
ArrowBody::Block(stmt) => {
|
|
362
376
|
let s = stmt.as_ref();
|
|
363
|
-
if let Statement::Return {
|
|
377
|
+
if let Statement::Return {
|
|
378
|
+
value: Some(ref e), ..
|
|
379
|
+
} = s
|
|
380
|
+
{
|
|
364
381
|
e
|
|
365
382
|
} else if let Statement::ExprStmt { expr: ref e, .. } = s {
|
|
366
383
|
e
|
|
@@ -376,9 +393,14 @@ impl<'a> Compiler<'a> {
|
|
|
376
393
|
}
|
|
377
394
|
}
|
|
378
395
|
// Binary: x op const or const op x
|
|
379
|
-
if let Expr::Binary {
|
|
380
|
-
|
|
381
|
-
|
|
396
|
+
if let Expr::Binary {
|
|
397
|
+
left, op, right, ..
|
|
398
|
+
} = expr_ref
|
|
399
|
+
{
|
|
400
|
+
let left_is_param =
|
|
401
|
+
matches!(left.as_ref(), Expr::Ident { name, .. } if name.as_ref() == param_name);
|
|
402
|
+
let right_is_param =
|
|
403
|
+
matches!(right.as_ref(), Expr::Ident { name, .. } if name.as_ref() == param_name);
|
|
382
404
|
let left_is_literal = matches!(left.as_ref(), Expr::Literal { .. });
|
|
383
405
|
let right_is_literal = matches!(right.as_ref(), Expr::Literal { .. });
|
|
384
406
|
if left_is_param && right_is_literal {
|
|
@@ -412,7 +434,10 @@ impl<'a> Compiler<'a> {
|
|
|
412
434
|
ArrowBody::Expr(e) => e.as_ref(),
|
|
413
435
|
ArrowBody::Block(stmt) => {
|
|
414
436
|
let s = stmt.as_ref();
|
|
415
|
-
if let Statement::Return {
|
|
437
|
+
if let Statement::Return {
|
|
438
|
+
value: Some(ref e), ..
|
|
439
|
+
} = s
|
|
440
|
+
{
|
|
416
441
|
e
|
|
417
442
|
} else if let Statement::ExprStmt { expr: ref e, .. } = s {
|
|
418
443
|
e
|
|
@@ -421,12 +446,29 @@ impl<'a> Compiler<'a> {
|
|
|
421
446
|
}
|
|
422
447
|
}
|
|
423
448
|
};
|
|
424
|
-
if let Expr::Binary {
|
|
425
|
-
|
|
449
|
+
if let Expr::Binary {
|
|
450
|
+
left, op, right, ..
|
|
451
|
+
} = expr_ref
|
|
452
|
+
{
|
|
453
|
+
if !matches!(
|
|
454
|
+
op,
|
|
455
|
+
BinOp::Eq
|
|
456
|
+
| BinOp::Ne
|
|
457
|
+
| BinOp::StrictEq
|
|
458
|
+
| BinOp::StrictNe
|
|
459
|
+
| BinOp::Lt
|
|
460
|
+
| BinOp::Le
|
|
461
|
+
| BinOp::Gt
|
|
462
|
+
| BinOp::Ge
|
|
463
|
+
| BinOp::And
|
|
464
|
+
| BinOp::Or
|
|
465
|
+
) {
|
|
426
466
|
return None;
|
|
427
467
|
}
|
|
428
|
-
let left_is_param =
|
|
429
|
-
|
|
468
|
+
let left_is_param =
|
|
469
|
+
matches!(left.as_ref(), Expr::Ident { name, .. } if name.as_ref() == param_name);
|
|
470
|
+
let right_is_param =
|
|
471
|
+
matches!(right.as_ref(), Expr::Ident { name, .. } if name.as_ref() == param_name);
|
|
430
472
|
let left_is_literal = matches!(left.as_ref(), Expr::Literal { .. });
|
|
431
473
|
let right_is_literal = matches!(right.as_ref(), Expr::Literal { .. });
|
|
432
474
|
if left_is_param && right_is_literal {
|
|
@@ -534,10 +576,9 @@ impl<'a> Compiler<'a> {
|
|
|
534
576
|
continue_patches: Vec::new(),
|
|
535
577
|
continue_is_forward_jump: false,
|
|
536
578
|
});
|
|
537
|
-
self.breakable_stack
|
|
538
|
-
.
|
|
539
|
-
|
|
540
|
-
});
|
|
579
|
+
self.breakable_stack.push(Breakable::Loop {
|
|
580
|
+
unwind_depth: self.block_depth,
|
|
581
|
+
});
|
|
541
582
|
self.compile_expr(cond)?;
|
|
542
583
|
let jump_out = self.emit_jump(Opcode::JumpIfFalse);
|
|
543
584
|
// JumpIfFalse already pops condition when taking body
|
|
@@ -580,10 +621,9 @@ impl<'a> Compiler<'a> {
|
|
|
580
621
|
continue_patches: Vec::new(),
|
|
581
622
|
continue_is_forward_jump: true,
|
|
582
623
|
});
|
|
583
|
-
self.breakable_stack
|
|
584
|
-
.
|
|
585
|
-
|
|
586
|
-
});
|
|
624
|
+
self.breakable_stack.push(Breakable::Loop {
|
|
625
|
+
unwind_depth: self.block_depth,
|
|
626
|
+
});
|
|
587
627
|
self.compile_statement(body)?;
|
|
588
628
|
let update_start = self.chunk.code.len();
|
|
589
629
|
if let Some(u) = update {
|
|
@@ -604,7 +644,12 @@ impl<'a> Compiler<'a> {
|
|
|
604
644
|
self.breakable_stack.pop();
|
|
605
645
|
self.scope.pop();
|
|
606
646
|
}
|
|
607
|
-
Statement::ForOf {
|
|
647
|
+
Statement::ForOf {
|
|
648
|
+
name,
|
|
649
|
+
iterable,
|
|
650
|
+
body,
|
|
651
|
+
..
|
|
652
|
+
} => {
|
|
608
653
|
self.compile_expr(iterable)?;
|
|
609
654
|
self.scope.push(HashMap::new());
|
|
610
655
|
let arr_name = Arc::from("__forof_arr__");
|
|
@@ -615,12 +660,18 @@ impl<'a> Compiler<'a> {
|
|
|
615
660
|
let len_idx = self.name_idx(&len_name);
|
|
616
661
|
let name_idx = self.name_idx(name);
|
|
617
662
|
self.emit_u16(Opcode::DeclareVar, arr_idx);
|
|
618
|
-
self.scope
|
|
663
|
+
self.scope
|
|
664
|
+
.last_mut()
|
|
665
|
+
.unwrap()
|
|
666
|
+
.insert(arr_name.clone(), false);
|
|
619
667
|
self.emit_u16(Opcode::LoadVar, arr_idx);
|
|
620
668
|
let len_name_idx = self.name_idx(&Arc::from("length"));
|
|
621
669
|
self.emit_u16(Opcode::GetMember, len_name_idx);
|
|
622
670
|
self.emit_u16(Opcode::DeclareVar, len_idx);
|
|
623
|
-
self.scope
|
|
671
|
+
self.scope
|
|
672
|
+
.last_mut()
|
|
673
|
+
.unwrap()
|
|
674
|
+
.insert(len_name.clone(), false);
|
|
624
675
|
let zero_idx = self.constant_idx(Constant::Number(0.0));
|
|
625
676
|
self.emit(Opcode::LoadConst);
|
|
626
677
|
self.chunk.write_u16(zero_idx);
|
|
@@ -632,15 +683,17 @@ impl<'a> Compiler<'a> {
|
|
|
632
683
|
continue_patches: Vec::new(),
|
|
633
684
|
continue_is_forward_jump: false,
|
|
634
685
|
});
|
|
635
|
-
self.breakable_stack
|
|
636
|
-
.
|
|
637
|
-
|
|
638
|
-
});
|
|
686
|
+
self.breakable_stack.push(Breakable::Loop {
|
|
687
|
+
unwind_depth: self.block_depth,
|
|
688
|
+
});
|
|
639
689
|
self.emit_u16(Opcode::LoadVar, arr_idx);
|
|
640
690
|
self.emit_u16(Opcode::LoadVar, i_idx);
|
|
641
691
|
self.emit(Opcode::GetIndex);
|
|
642
692
|
self.emit_u16(Opcode::DeclareVar, name_idx);
|
|
643
|
-
self.scope
|
|
693
|
+
self.scope
|
|
694
|
+
.last_mut()
|
|
695
|
+
.unwrap()
|
|
696
|
+
.insert(Arc::clone(name), false);
|
|
644
697
|
self.compile_statement(body)?;
|
|
645
698
|
self.emit_u16(Opcode::LoadVar, i_idx);
|
|
646
699
|
let one_idx = self.constant_idx(Constant::Number(1.0));
|
|
@@ -678,9 +731,8 @@ impl<'a> Compiler<'a> {
|
|
|
678
731
|
}
|
|
679
732
|
Statement::Break { .. } => {
|
|
680
733
|
let unwind_depth = match self.breakable_stack.last() {
|
|
681
|
-
Some(Breakable::Loop { unwind_depth })
|
|
682
|
-
|
|
683
|
-
}
|
|
734
|
+
Some(Breakable::Loop { unwind_depth })
|
|
735
|
+
| Some(Breakable::Switch { unwind_depth }) => *unwind_depth,
|
|
684
736
|
None => {
|
|
685
737
|
return Err(CompileError {
|
|
686
738
|
message: "break not inside a loop or switch".to_string(),
|
|
@@ -694,7 +746,11 @@ impl<'a> Compiler<'a> {
|
|
|
694
746
|
self.loop_stack.last_mut().unwrap().break_patches.push(pos);
|
|
695
747
|
}
|
|
696
748
|
Some(Breakable::Switch { .. }) => {
|
|
697
|
-
self.switch_stack
|
|
749
|
+
self.switch_stack
|
|
750
|
+
.last_mut()
|
|
751
|
+
.unwrap()
|
|
752
|
+
.break_patches
|
|
753
|
+
.push(pos);
|
|
698
754
|
}
|
|
699
755
|
None => {}
|
|
700
756
|
}
|
|
@@ -764,7 +820,10 @@ impl<'a> Compiler<'a> {
|
|
|
764
820
|
self.chunk.write_u16(idx);
|
|
765
821
|
let idx = self.name_idx(name);
|
|
766
822
|
self.emit_u16(Opcode::DeclareVar, idx);
|
|
767
|
-
self.scope
|
|
823
|
+
self.scope
|
|
824
|
+
.last_mut()
|
|
825
|
+
.unwrap()
|
|
826
|
+
.insert(Arc::clone(name), false);
|
|
768
827
|
}
|
|
769
828
|
Statement::DoWhile { body, cond, .. } => {
|
|
770
829
|
let start = self.chunk.code.len();
|
|
@@ -773,10 +832,9 @@ impl<'a> Compiler<'a> {
|
|
|
773
832
|
continue_patches: Vec::new(),
|
|
774
833
|
continue_is_forward_jump: false,
|
|
775
834
|
});
|
|
776
|
-
self.breakable_stack
|
|
777
|
-
.
|
|
778
|
-
|
|
779
|
-
});
|
|
835
|
+
self.breakable_stack.push(Breakable::Loop {
|
|
836
|
+
unwind_depth: self.block_depth,
|
|
837
|
+
});
|
|
780
838
|
self.compile_statement(body)?;
|
|
781
839
|
let cond_start = self.chunk.code.len();
|
|
782
840
|
self.compile_expr(cond)?;
|
|
@@ -794,7 +852,12 @@ impl<'a> Compiler<'a> {
|
|
|
794
852
|
self.patch_jump(p, end);
|
|
795
853
|
}
|
|
796
854
|
}
|
|
797
|
-
Statement::Switch {
|
|
855
|
+
Statement::Switch {
|
|
856
|
+
expr,
|
|
857
|
+
cases,
|
|
858
|
+
default_body,
|
|
859
|
+
..
|
|
860
|
+
} => {
|
|
798
861
|
let switch_unwind_depth = self.block_depth;
|
|
799
862
|
self.switch_stack.push(SwitchInfo {
|
|
800
863
|
break_patches: Vec::new(),
|
|
@@ -899,7 +962,8 @@ impl<'a> Compiler<'a> {
|
|
|
899
962
|
if let Some(finally) = finally_body {
|
|
900
963
|
self.compile_statement(finally)?;
|
|
901
964
|
}
|
|
902
|
-
let catch_offset =
|
|
965
|
+
let catch_offset =
|
|
966
|
+
catch_start.wrapping_sub(catch_offset_pos).wrapping_sub(3) as u16;
|
|
903
967
|
self.chunk.code[catch_offset_pos + 1] = (catch_offset >> 8) as u8;
|
|
904
968
|
self.chunk.code[catch_offset_pos + 2] = (catch_offset & 0xff) as u8;
|
|
905
969
|
}
|
|
@@ -1008,7 +1072,9 @@ impl<'a> Compiler<'a> {
|
|
|
1008
1072
|
let idx = self.name_idx(name);
|
|
1009
1073
|
self.emit_u16(Opcode::LoadVar, idx);
|
|
1010
1074
|
}
|
|
1011
|
-
Expr::Binary {
|
|
1075
|
+
Expr::Binary {
|
|
1076
|
+
left, op, right, ..
|
|
1077
|
+
} => {
|
|
1012
1078
|
match op {
|
|
1013
1079
|
BinOp::And => {
|
|
1014
1080
|
// Short-circuit: a && b => if !a then a else b
|
|
@@ -1049,16 +1115,29 @@ impl<'a> Compiler<'a> {
|
|
|
1049
1115
|
&& args.len() == 1
|
|
1050
1116
|
&& matches!(args[0], CallArg::Expr(_))
|
|
1051
1117
|
{
|
|
1052
|
-
if let (
|
|
1053
|
-
|
|
1118
|
+
if let (
|
|
1119
|
+
Expr::Member {
|
|
1120
|
+
object,
|
|
1121
|
+
prop: MemberProp::Name(key),
|
|
1122
|
+
optional: false,
|
|
1123
|
+
..
|
|
1124
|
+
},
|
|
1125
|
+
CallArg::Expr(cmp_expr),
|
|
1126
|
+
) = (callee.as_ref(), &args[0])
|
|
1054
1127
|
{
|
|
1055
1128
|
if key.as_ref() == "sort" {
|
|
1056
|
-
if let Some(ascending) = Self::detect_numeric_sort_comparator(cmp_expr)
|
|
1129
|
+
if let Some(ascending) = Self::detect_numeric_sort_comparator(cmp_expr)
|
|
1130
|
+
{
|
|
1057
1131
|
self.compile_expr(object)?;
|
|
1058
|
-
self.emit_u8(
|
|
1132
|
+
self.emit_u8(
|
|
1133
|
+
Opcode::ArraySortNumeric,
|
|
1134
|
+
if ascending { 0 } else { 1 },
|
|
1135
|
+
);
|
|
1059
1136
|
return Ok(());
|
|
1060
1137
|
}
|
|
1061
|
-
if let Some((prop, ascending)) =
|
|
1138
|
+
if let Some((prop, ascending)) =
|
|
1139
|
+
Self::detect_property_sort_comparator(cmp_expr)
|
|
1140
|
+
{
|
|
1062
1141
|
self.compile_expr(object)?;
|
|
1063
1142
|
let prop_idx = self.constant_idx(Constant::String(prop));
|
|
1064
1143
|
self.emit(Opcode::ArraySortByProperty);
|
|
@@ -1211,7 +1290,9 @@ impl<'a> Compiler<'a> {
|
|
|
1211
1290
|
self.patch_jump(jump_end, self.chunk.code.len());
|
|
1212
1291
|
}
|
|
1213
1292
|
Expr::Array { elements, .. } => {
|
|
1214
|
-
let has_spread = elements
|
|
1293
|
+
let has_spread = elements
|
|
1294
|
+
.iter()
|
|
1295
|
+
.any(|e| matches!(e, ArrayElement::Spread(_)));
|
|
1215
1296
|
if has_spread {
|
|
1216
1297
|
// Build array incrementally: start with [], concat each element
|
|
1217
1298
|
self.emit_u16(Opcode::NewArray, 0);
|
|
@@ -1376,7 +1457,9 @@ impl<'a> Compiler<'a> {
|
|
|
1376
1457
|
self.emit(Opcode::Dup);
|
|
1377
1458
|
self.emit_u16(Opcode::StoreVar, idx);
|
|
1378
1459
|
}
|
|
1379
|
-
Expr::CompoundAssign {
|
|
1460
|
+
Expr::CompoundAssign {
|
|
1461
|
+
name, op, value, ..
|
|
1462
|
+
} => {
|
|
1380
1463
|
let idx = self.name_idx(name);
|
|
1381
1464
|
self.emit_u16(Opcode::LoadVar, idx);
|
|
1382
1465
|
self.compile_expr(value)?;
|
|
@@ -1384,20 +1467,32 @@ impl<'a> Compiler<'a> {
|
|
|
1384
1467
|
self.emit(Opcode::Dup);
|
|
1385
1468
|
self.emit_u16(Opcode::StoreVar, idx);
|
|
1386
1469
|
}
|
|
1387
|
-
Expr::MemberAssign {
|
|
1470
|
+
Expr::MemberAssign {
|
|
1471
|
+
object,
|
|
1472
|
+
prop,
|
|
1473
|
+
value,
|
|
1474
|
+
..
|
|
1475
|
+
} => {
|
|
1388
1476
|
self.compile_expr(object)?;
|
|
1389
1477
|
self.compile_expr(value)?;
|
|
1390
1478
|
let idx = self.name_idx(prop);
|
|
1391
1479
|
self.emit_u16(Opcode::SetMember, idx); // SetMember pops obj, val and pushes val back
|
|
1392
1480
|
}
|
|
1393
|
-
Expr::IndexAssign {
|
|
1481
|
+
Expr::IndexAssign {
|
|
1482
|
+
object,
|
|
1483
|
+
index,
|
|
1484
|
+
value,
|
|
1485
|
+
..
|
|
1486
|
+
} => {
|
|
1394
1487
|
self.compile_expr(object)?;
|
|
1395
1488
|
self.compile_expr(index)?;
|
|
1396
1489
|
self.compile_expr(value)?;
|
|
1397
1490
|
self.emit(Opcode::Dup); // leave copy for assignment expression result
|
|
1398
1491
|
self.emit(Opcode::SetIndex);
|
|
1399
1492
|
}
|
|
1400
|
-
Expr::NativeModuleLoad {
|
|
1493
|
+
Expr::NativeModuleLoad {
|
|
1494
|
+
spec, export_name, ..
|
|
1495
|
+
} => {
|
|
1401
1496
|
let spec_idx = self.constant_idx(Constant::String(Arc::clone(spec)));
|
|
1402
1497
|
let export_idx = self.constant_idx(Constant::String(Arc::clone(export_name)));
|
|
1403
1498
|
self.emit(Opcode::LoadNativeExport);
|
|
@@ -1405,7 +1500,10 @@ impl<'a> Compiler<'a> {
|
|
|
1405
1500
|
self.chunk.write_u16(export_idx);
|
|
1406
1501
|
}
|
|
1407
1502
|
Expr::JsxElement {
|
|
1408
|
-
tag,
|
|
1503
|
+
tag,
|
|
1504
|
+
props,
|
|
1505
|
+
children,
|
|
1506
|
+
..
|
|
1409
1507
|
} => {
|
|
1410
1508
|
self.compile_jsx_element(tag, props, children)?;
|
|
1411
1509
|
}
|
|
@@ -1422,7 +1520,9 @@ impl<'a> Compiler<'a> {
|
|
|
1422
1520
|
self.compile_expr(operand)?;
|
|
1423
1521
|
self.emit_u16(Opcode::Call, 1);
|
|
1424
1522
|
}
|
|
1425
|
-
Expr::LogicalAssign {
|
|
1523
|
+
Expr::LogicalAssign {
|
|
1524
|
+
name, op, value, ..
|
|
1525
|
+
} => {
|
|
1426
1526
|
let idx = self.name_idx(name);
|
|
1427
1527
|
match op {
|
|
1428
1528
|
LogicalAssignOp::OrOr => {
|
|
@@ -1515,7 +1615,11 @@ impl<'a> Compiler<'a> {
|
|
|
1515
1615
|
let h_idx = self.name_idx(&Arc::from("h"));
|
|
1516
1616
|
self.emit_u16(Opcode::LoadGlobal, h_idx);
|
|
1517
1617
|
let tag_str = tag.as_ref();
|
|
1518
|
-
let is_component = tag_str
|
|
1618
|
+
let is_component = tag_str
|
|
1619
|
+
.chars()
|
|
1620
|
+
.next()
|
|
1621
|
+
.map(|c| c.is_uppercase())
|
|
1622
|
+
.unwrap_or(false);
|
|
1519
1623
|
if is_component {
|
|
1520
1624
|
let tag_idx = self.name_idx(tag);
|
|
1521
1625
|
self.emit_u16(Opcode::LoadGlobal, tag_idx);
|
|
@@ -109,10 +109,19 @@ impl Opcode {
|
|
|
109
109
|
/// Size in bytes of this instruction at `ip` (including operands). Returns None if truncated.
|
|
110
110
|
pub fn instruction_size(self, code: &[u8], ip: usize) -> Option<usize> {
|
|
111
111
|
let size = match self {
|
|
112
|
-
Opcode::Nop
|
|
113
|
-
| Opcode::
|
|
114
|
-
| Opcode::
|
|
115
|
-
|
|
112
|
+
Opcode::Nop
|
|
113
|
+
| Opcode::Pop
|
|
114
|
+
| Opcode::Dup
|
|
115
|
+
| Opcode::Return
|
|
116
|
+
| Opcode::ExitTry
|
|
117
|
+
| Opcode::ArrayMapIdentity
|
|
118
|
+
| Opcode::CallSpread
|
|
119
|
+
| Opcode::ConstructSpread
|
|
120
|
+
| Opcode::EnterBlock
|
|
121
|
+
| Opcode::ExitBlock => 1,
|
|
122
|
+
Opcode::ArraySortByProperty
|
|
123
|
+
| Opcode::ArrayMapBinOp
|
|
124
|
+
| Opcode::ArrayFilterBinOp
|
|
116
125
|
| Opcode::LoadNativeExport => 5,
|
|
117
126
|
_ => 3,
|
|
118
127
|
};
|
|
@@ -162,8 +162,8 @@ fn chain_jumps(code: &mut [u8]) {
|
|
|
162
162
|
let current_offset = read_i16(code, ip + 1) as isize;
|
|
163
163
|
let current_target = (ip as isize + 3 + current_offset).max(0) as usize;
|
|
164
164
|
if let Some(final_target) = final_jump_target(code, ip) {
|
|
165
|
-
let target_ok =
|
|
166
|
-
|| insn_starts.contains(&final_target);
|
|
165
|
+
let target_ok =
|
|
166
|
+
final_target == code.len() || insn_starts.contains(&final_target);
|
|
167
167
|
if final_target != current_target && target_ok {
|
|
168
168
|
let new_offset = final_target as i32 - (ip + 3) as i32;
|
|
169
169
|
if (i16::MIN as i32..=i16::MAX as i32).contains(&new_offset) {
|