@tishlang/tish 1.9.2 → 1.12.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/bin/tish +0 -0
- package/crates/js_to_tish/src/transform/expr.rs +8 -6
- package/crates/js_to_tish/src/transform/stmt.rs +12 -13
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cargo_native_registry.rs +4 -1
- package/crates/tish/src/cli_help.rs +9 -1
- package/crates/tish/src/main.rs +66 -11
- package/crates/tish/tests/integration_test.rs +145 -7
- package/crates/tish_ast/src/ast.rs +3 -9
- package/crates/tish_build_utils/src/lib.rs +74 -23
- package/crates/tish_builtins/src/array.rs +2 -3
- package/crates/tish_builtins/src/construct.rs +15 -28
- package/crates/tish_builtins/src/globals.rs +18 -16
- package/crates/tish_builtins/src/helpers.rs +1 -4
- package/crates/tish_builtins/src/lib.rs +1 -0
- package/crates/tish_builtins/src/math.rs +7 -0
- package/crates/tish_builtins/src/object.rs +10 -10
- package/crates/tish_builtins/src/string.rs +27 -3
- package/crates/tish_builtins/src/symbol.rs +83 -0
- package/crates/tish_compile/src/codegen.rs +324 -158
- package/crates/tish_compile/src/lib.rs +39 -7
- package/crates/tish_compile/src/resolve.rs +191 -6
- package/crates/tish_compile/src/types.rs +6 -6
- package/crates/tish_compile_js/src/codegen.rs +8 -5
- package/crates/tish_core/src/console_style.rs +9 -0
- package/crates/tish_core/src/json.rs +17 -7
- package/crates/tish_core/src/macros.rs +2 -2
- package/crates/tish_core/src/value.rs +213 -4
- package/crates/tish_cranelift/src/link.rs +1 -1
- package/crates/tish_cranelift_runtime/Cargo.toml +4 -0
- package/crates/tish_eval/src/eval.rs +135 -73
- package/crates/tish_eval/src/http.rs +18 -12
- package/crates/tish_eval/src/lib.rs +29 -0
- package/crates/tish_eval/src/regex.rs +1 -1
- package/crates/tish_eval/src/value.rs +89 -4
- package/crates/tish_eval/src/value_convert.rs +30 -8
- package/crates/tish_fmt/src/lib.rs +4 -1
- package/crates/tish_lexer/src/lib.rs +7 -2
- package/crates/tish_llvm/src/lib.rs +2 -2
- package/crates/tish_lsp/src/builtin_goto.rs +111 -10
- package/crates/tish_lsp/src/import_goto.rs +35 -22
- package/crates/tish_lsp/src/main.rs +118 -85
- package/crates/tish_native/src/build.rs +270 -24
- package/crates/tish_native/src/config.rs +48 -0
- package/crates/tish_native/src/lib.rs +139 -12
- package/crates/tish_parser/src/lib.rs +5 -2
- package/crates/tish_parser/src/parser.rs +45 -75
- package/crates/tish_pg/src/error.rs +1 -1
- package/crates/tish_pg/src/lib.rs +61 -73
- package/crates/tish_resolve/src/lib.rs +283 -158
- package/crates/tish_resolve/src/pos.rs +10 -2
- package/crates/tish_runtime/Cargo.toml +3 -0
- package/crates/tish_runtime/src/http.rs +39 -39
- package/crates/tish_runtime/src/http_fetch.rs +12 -12
- package/crates/tish_runtime/src/lib.rs +35 -44
- package/crates/tish_runtime/src/native_promise.rs +0 -11
- package/crates/tish_runtime/src/promise.rs +14 -1
- package/crates/tish_runtime/src/promise_io.rs +1 -4
- package/crates/tish_runtime/src/timers.rs +12 -7
- package/crates/tish_runtime/src/ws.rs +40 -27
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +10 -8
- package/crates/tish_ui/src/jsx.rs +6 -4
- package/crates/tish_ui/src/lib.rs +5 -4
- package/crates/tish_ui/src/runtime/hooks.rs +123 -37
- package/crates/tish_ui/src/runtime/mod.rs +21 -41
- package/crates/tish_vm/Cargo.toml +2 -0
- package/crates/tish_vm/src/vm.rs +258 -153
- package/crates/tish_wasm/src/lib.rs +60 -7
- package/crates/tish_wasm_runtime/Cargo.toml +10 -1
- package/crates/tish_wasm_runtime/src/gpu.rs +413 -0
- package/crates/tish_wasm_runtime/src/lib.rs +7 -1
- package/crates/tishlang_cargo_bindgen/src/classify.rs +1 -3
- package/crates/tishlang_cargo_bindgen/src/discover.rs +10 -5
- package/crates/tishlang_cargo_bindgen/src/infer.rs +18 -8
- package/crates/tishlang_cargo_bindgen/src/lib.rs +25 -26
- package/crates/tishlang_cargo_bindgen/src/main.rs +41 -38
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +4 -1
- package/justfile +3 -3
- 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
package/crates/tish_vm/src/vm.rs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
//! Stack-based bytecode VM.
|
|
2
2
|
|
|
3
|
-
use std::cell::RefCell;
|
|
4
|
-
use tishlang_core::VmRef;
|
|
5
3
|
use std::collections::{HashMap, HashSet};
|
|
6
|
-
use std::rc::Rc;
|
|
7
4
|
use std::sync::Arc;
|
|
8
5
|
|
|
6
|
+
#[cfg(not(feature = "send-values"))]
|
|
7
|
+
use std::rc::Rc;
|
|
8
|
+
use tishlang_core::VmRef;
|
|
9
|
+
|
|
9
10
|
use tishlang_ast::{BinOp, UnaryOp};
|
|
10
11
|
use tishlang_builtins::array as arr_builtins;
|
|
11
12
|
use tishlang_builtins::construct as construct_builtin;
|
|
@@ -13,7 +14,9 @@ use tishlang_builtins::globals as globals_builtins;
|
|
|
13
14
|
use tishlang_builtins::math as math_builtins;
|
|
14
15
|
use tishlang_builtins::string as str_builtins;
|
|
15
16
|
use tishlang_bytecode::{u8_to_binop, u8_to_unaryop, Chunk, Constant, Opcode, NO_REST_PARAM};
|
|
16
|
-
use tishlang_core::{
|
|
17
|
+
use tishlang_core::{
|
|
18
|
+
merge_object_data, object_get, object_has, object_set, NativeFn, ObjectData, ObjectMap, Value,
|
|
19
|
+
};
|
|
17
20
|
|
|
18
21
|
/// Wrap a closure in the right shared pointer for the current build.
|
|
19
22
|
/// Under `send-values` that's `Arc<dyn Fn + Send + Sync>`; otherwise it's
|
|
@@ -46,12 +49,27 @@ type ArrayMethodFn = NativeFn;
|
|
|
46
49
|
not(any(
|
|
47
50
|
feature = "fs",
|
|
48
51
|
feature = "http",
|
|
52
|
+
feature = "promise",
|
|
49
53
|
feature = "timers",
|
|
50
54
|
feature = "process",
|
|
51
55
|
feature = "ws"
|
|
52
56
|
)),
|
|
53
57
|
allow(dead_code)
|
|
54
58
|
)]
|
|
59
|
+
#[inline]
|
|
60
|
+
fn value_object_from_map(m: ObjectMap) -> Value {
|
|
61
|
+
Value::Object(VmRef::new(ObjectData::from_strings(m)))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#[cfg(any(
|
|
65
|
+
feature = "fs",
|
|
66
|
+
feature = "http",
|
|
67
|
+
feature = "promise",
|
|
68
|
+
feature = "timers",
|
|
69
|
+
feature = "process",
|
|
70
|
+
feature = "ws"
|
|
71
|
+
))]
|
|
72
|
+
#[inline]
|
|
55
73
|
fn cap_allows(enabled: &HashSet<String>, name: &str) -> bool {
|
|
56
74
|
enabled.contains("full") || enabled.contains(name)
|
|
57
75
|
}
|
|
@@ -62,6 +80,8 @@ pub fn all_compiled_capabilities() -> HashSet<String> {
|
|
|
62
80
|
let mut s = HashSet::new();
|
|
63
81
|
#[cfg(feature = "http")]
|
|
64
82
|
s.insert("http".to_string());
|
|
83
|
+
#[cfg(feature = "promise")]
|
|
84
|
+
s.insert("promise".to_string());
|
|
65
85
|
#[cfg(feature = "timers")]
|
|
66
86
|
s.insert("timers".to_string());
|
|
67
87
|
#[cfg(feature = "fs")]
|
|
@@ -80,6 +100,7 @@ pub fn all_compiled_capabilities() -> HashSet<String> {
|
|
|
80
100
|
not(any(
|
|
81
101
|
feature = "fs",
|
|
82
102
|
feature = "http",
|
|
103
|
+
feature = "promise",
|
|
83
104
|
feature = "timers",
|
|
84
105
|
feature = "process",
|
|
85
106
|
feature = "ws"
|
|
@@ -136,12 +157,12 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
|
|
|
136
157
|
Value::Object(ref obj) => {
|
|
137
158
|
let obj_ref = obj.borrow();
|
|
138
159
|
if let Some(Value::Function(on_worker)) =
|
|
139
|
-
obj_ref.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
160
|
+
obj_ref.strings.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
140
161
|
{
|
|
141
162
|
let args_for_init = [Value::Number(0.0)];
|
|
142
163
|
on_worker(&args_for_init)
|
|
143
164
|
} else if let Some(h) =
|
|
144
|
-
obj_ref.get(&std::sync::Arc::from("handler")).cloned()
|
|
165
|
+
obj_ref.strings.get(&std::sync::Arc::from("handler")).cloned()
|
|
145
166
|
{
|
|
146
167
|
h
|
|
147
168
|
} else {
|
|
@@ -159,6 +180,16 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
|
|
|
159
180
|
_ => None,
|
|
160
181
|
};
|
|
161
182
|
}
|
|
183
|
+
#[cfg(all(feature = "promise", not(feature = "http")))]
|
|
184
|
+
if spec == "tish:http" && cap_allows(enabled, "promise") {
|
|
185
|
+
return match export_name {
|
|
186
|
+
"Promise" => Some(tishlang_runtime::promise_object()),
|
|
187
|
+
"await" => Some(Value::native(|args: &[Value]| {
|
|
188
|
+
tishlang_runtime::await_promise(args.first().cloned().unwrap_or(Value::Null))
|
|
189
|
+
})),
|
|
190
|
+
_ => None,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
162
193
|
#[cfg(feature = "timers")]
|
|
163
194
|
if spec == "tish:timers" && cap_allows(enabled, "timers") {
|
|
164
195
|
return match export_name {
|
|
@@ -192,30 +223,24 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
|
|
|
192
223
|
"argv" => Some(Value::Array(VmRef::new(
|
|
193
224
|
std::env::args().map(|s| Value::String(s.into())).collect(),
|
|
194
225
|
))),
|
|
195
|
-
"env" => Some(
|
|
226
|
+
"env" => Some(value_object_from_map(
|
|
196
227
|
std::env::vars()
|
|
197
228
|
.map(|(k, v)| (Arc::from(k.as_str()), Value::String(v.into())))
|
|
198
229
|
.collect(),
|
|
199
|
-
))
|
|
230
|
+
)),
|
|
200
231
|
"process" => {
|
|
201
232
|
let mut m = ObjectMap::default();
|
|
202
233
|
m.insert(
|
|
203
234
|
"exit".into(),
|
|
204
|
-
Value::native(|args: &[Value]|
|
|
205
|
-
tishlang_runtime::process_exit(args)
|
|
206
|
-
}),
|
|
235
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_exit(args)),
|
|
207
236
|
);
|
|
208
237
|
m.insert(
|
|
209
238
|
"cwd".into(),
|
|
210
|
-
Value::native(|args: &[Value]|
|
|
211
|
-
tishlang_runtime::process_cwd(args)
|
|
212
|
-
}),
|
|
239
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_cwd(args)),
|
|
213
240
|
);
|
|
214
241
|
m.insert(
|
|
215
242
|
"exec".into(),
|
|
216
|
-
Value::native(|args: &[Value]|
|
|
217
|
-
tishlang_runtime::process_exec(args)
|
|
218
|
-
}),
|
|
243
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_exec(args)),
|
|
219
244
|
);
|
|
220
245
|
m.insert(
|
|
221
246
|
"argv".into(),
|
|
@@ -225,13 +250,13 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
|
|
|
225
250
|
);
|
|
226
251
|
m.insert(
|
|
227
252
|
"env".into(),
|
|
228
|
-
|
|
253
|
+
value_object_from_map(
|
|
229
254
|
std::env::vars()
|
|
230
255
|
.map(|(k, v)| (Arc::from(k.as_str()), Value::String(v.into())))
|
|
231
256
|
.collect(),
|
|
232
|
-
)
|
|
257
|
+
),
|
|
233
258
|
);
|
|
234
|
-
Some(
|
|
259
|
+
Some(value_object_from_map(m))
|
|
235
260
|
}
|
|
236
261
|
_ => None,
|
|
237
262
|
};
|
|
@@ -342,10 +367,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
342
367
|
Value::Null
|
|
343
368
|
}),
|
|
344
369
|
);
|
|
345
|
-
g.insert(
|
|
346
|
-
"console".into(),
|
|
347
|
-
Value::Object(VmRef::new(console)),
|
|
348
|
-
);
|
|
370
|
+
g.insert("console".into(), value_object_from_map(console));
|
|
349
371
|
|
|
350
372
|
let mut math = ObjectMap::default();
|
|
351
373
|
math.insert(
|
|
@@ -433,9 +455,49 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
433
455
|
"trunc".into(),
|
|
434
456
|
Value::native(|args: &[Value]| math_builtins::trunc(args)),
|
|
435
457
|
);
|
|
458
|
+
// Trig/hypot not covered by `math_builtins`; needed by the 3D engine's
|
|
459
|
+
// camera + character-controller math (atan2/hypot) on the wasm VM, where
|
|
460
|
+
// (unlike `--target js`) there is no host `Math` to fall through to.
|
|
461
|
+
math.insert(
|
|
462
|
+
"atan2".into(),
|
|
463
|
+
Value::native(|args: &[Value]| {
|
|
464
|
+
let y = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
465
|
+
let x = args.get(1).and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
466
|
+
Value::Number(y.atan2(x))
|
|
467
|
+
}),
|
|
468
|
+
);
|
|
469
|
+
math.insert(
|
|
470
|
+
"atan".into(),
|
|
471
|
+
Value::native(|args: &[Value]| {
|
|
472
|
+
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
473
|
+
Value::Number(n.atan())
|
|
474
|
+
}),
|
|
475
|
+
);
|
|
476
|
+
math.insert(
|
|
477
|
+
"asin".into(),
|
|
478
|
+
Value::native(|args: &[Value]| {
|
|
479
|
+
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
480
|
+
Value::Number(n.asin())
|
|
481
|
+
}),
|
|
482
|
+
);
|
|
483
|
+
math.insert(
|
|
484
|
+
"acos".into(),
|
|
485
|
+
Value::native(|args: &[Value]| {
|
|
486
|
+
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
487
|
+
Value::Number(n.acos())
|
|
488
|
+
}),
|
|
489
|
+
);
|
|
490
|
+
math.insert(
|
|
491
|
+
"hypot".into(),
|
|
492
|
+
Value::native(|args: &[Value]| {
|
|
493
|
+
let nums: Vec<f64> = args.iter().filter_map(|v| v.as_number()).collect();
|
|
494
|
+
let sum_sq: f64 = nums.iter().map(|n| n * n).sum();
|
|
495
|
+
Value::Number(sum_sq.sqrt())
|
|
496
|
+
}),
|
|
497
|
+
);
|
|
436
498
|
math.insert("PI".into(), Value::Number(std::f64::consts::PI));
|
|
437
499
|
math.insert("E".into(), Value::Number(std::f64::consts::E));
|
|
438
|
-
g.insert("Math".into(),
|
|
500
|
+
g.insert("Math".into(), value_object_from_map(math));
|
|
439
501
|
|
|
440
502
|
let mut json = ObjectMap::default();
|
|
441
503
|
json.insert(
|
|
@@ -455,7 +517,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
455
517
|
Value::String(tishlang_core::json_stringify(v).into())
|
|
456
518
|
}),
|
|
457
519
|
);
|
|
458
|
-
g.insert("JSON".into(),
|
|
520
|
+
g.insert("JSON".into(), value_object_from_map(json));
|
|
459
521
|
|
|
460
522
|
g.insert(
|
|
461
523
|
"parseInt".into(),
|
|
@@ -463,9 +525,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
463
525
|
);
|
|
464
526
|
g.insert(
|
|
465
527
|
"parseFloat".into(),
|
|
466
|
-
Value::native(|args: &[Value]|
|
|
467
|
-
globals_builtins::parse_float(args)
|
|
468
|
-
}),
|
|
528
|
+
Value::native(|args: &[Value]| globals_builtins::parse_float(args)),
|
|
469
529
|
);
|
|
470
530
|
g.insert(
|
|
471
531
|
"encodeURI".into(),
|
|
@@ -502,6 +562,10 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
502
562
|
Value::String(v.type_name().into())
|
|
503
563
|
}),
|
|
504
564
|
);
|
|
565
|
+
g.insert(
|
|
566
|
+
"Symbol".into(),
|
|
567
|
+
tishlang_builtins::symbol::symbol_object(),
|
|
568
|
+
);
|
|
505
569
|
|
|
506
570
|
// Date - at minimum Date.now() for timing
|
|
507
571
|
let mut date = ObjectMap::default();
|
|
@@ -515,7 +579,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
515
579
|
Value::Number(ms)
|
|
516
580
|
}),
|
|
517
581
|
);
|
|
518
|
-
g.insert("Date".into(),
|
|
582
|
+
g.insert("Date".into(), value_object_from_map(date));
|
|
519
583
|
|
|
520
584
|
g.insert(
|
|
521
585
|
"Uint8Array".into(),
|
|
@@ -530,77 +594,49 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
530
594
|
let mut object_methods = ObjectMap::default();
|
|
531
595
|
object_methods.insert(
|
|
532
596
|
"assign".into(),
|
|
533
|
-
Value::native(|args: &[Value]|
|
|
534
|
-
globals_builtins::object_assign(args)
|
|
535
|
-
}),
|
|
597
|
+
Value::native(|args: &[Value]| globals_builtins::object_assign(args)),
|
|
536
598
|
);
|
|
537
599
|
object_methods.insert(
|
|
538
600
|
"fromEntries".into(),
|
|
539
|
-
Value::native(|args: &[Value]|
|
|
540
|
-
globals_builtins::object_from_entries(args)
|
|
541
|
-
}),
|
|
601
|
+
Value::native(|args: &[Value]| globals_builtins::object_from_entries(args)),
|
|
542
602
|
);
|
|
543
603
|
object_methods.insert(
|
|
544
604
|
"keys".into(),
|
|
545
|
-
Value::native(|args: &[Value]|
|
|
546
|
-
globals_builtins::object_keys(args)
|
|
547
|
-
}),
|
|
605
|
+
Value::native(|args: &[Value]| globals_builtins::object_keys(args)),
|
|
548
606
|
);
|
|
549
607
|
object_methods.insert(
|
|
550
608
|
"values".into(),
|
|
551
|
-
Value::native(|args: &[Value]|
|
|
552
|
-
globals_builtins::object_values(args)
|
|
553
|
-
}),
|
|
609
|
+
Value::native(|args: &[Value]| globals_builtins::object_values(args)),
|
|
554
610
|
);
|
|
555
611
|
object_methods.insert(
|
|
556
612
|
"entries".into(),
|
|
557
|
-
Value::native(|args: &[Value]|
|
|
558
|
-
globals_builtins::object_entries(args)
|
|
559
|
-
}),
|
|
560
|
-
);
|
|
561
|
-
g.insert(
|
|
562
|
-
"Object".into(),
|
|
563
|
-
Value::Object(VmRef::new(object_methods)),
|
|
613
|
+
Value::native(|args: &[Value]| globals_builtins::object_entries(args)),
|
|
564
614
|
);
|
|
615
|
+
g.insert("Object".into(), value_object_from_map(object_methods));
|
|
565
616
|
|
|
566
617
|
// Array.isArray
|
|
567
618
|
let mut array_static = ObjectMap::default();
|
|
568
619
|
array_static.insert(
|
|
569
620
|
"isArray".into(),
|
|
570
|
-
Value::native(|args: &[Value]|
|
|
571
|
-
globals_builtins::array_is_array(args)
|
|
572
|
-
}),
|
|
573
|
-
);
|
|
574
|
-
g.insert(
|
|
575
|
-
"Array".into(),
|
|
576
|
-
Value::Object(VmRef::new(array_static)),
|
|
621
|
+
Value::native(|args: &[Value]| globals_builtins::array_is_array(args)),
|
|
577
622
|
);
|
|
623
|
+
g.insert("Array".into(), value_object_from_map(array_static));
|
|
578
624
|
|
|
579
625
|
// String(value) as callable + String.fromCharCode
|
|
580
|
-
let string_convert_fn = Value::native(|args: &[Value]|
|
|
581
|
-
globals_builtins::string_convert(args)
|
|
582
|
-
});
|
|
626
|
+
let string_convert_fn = Value::native(|args: &[Value]| globals_builtins::string_convert(args));
|
|
583
627
|
let mut string_static = ObjectMap::default();
|
|
584
628
|
string_static.insert(
|
|
585
629
|
"fromCharCode".into(),
|
|
586
|
-
Value::native(|args: &[Value]|
|
|
587
|
-
globals_builtins::string_from_char_code(args)
|
|
588
|
-
}),
|
|
630
|
+
Value::native(|args: &[Value]| globals_builtins::string_from_char_code(args)),
|
|
589
631
|
);
|
|
590
632
|
string_static.insert(Arc::from("__call"), string_convert_fn);
|
|
591
|
-
g.insert(
|
|
592
|
-
"String".into(),
|
|
593
|
-
Value::Object(VmRef::new(string_static)),
|
|
594
|
-
);
|
|
633
|
+
g.insert("String".into(), value_object_from_map(string_static));
|
|
595
634
|
|
|
596
635
|
// JSX / Lattish: stubs for bytecode VM when no DOM (e.g. console). Override via set_global in browser.
|
|
597
|
-
g.insert(
|
|
598
|
-
"h".into(),
|
|
599
|
-
Value::native(|_args: &[Value]| Value::Null),
|
|
600
|
-
);
|
|
636
|
+
g.insert("h".into(), Value::native(|_args: &[Value]| Value::Null));
|
|
601
637
|
g.insert(
|
|
602
638
|
"Fragment".into(),
|
|
603
|
-
|
|
639
|
+
value_object_from_map(ObjectMap::default()),
|
|
604
640
|
);
|
|
605
641
|
g.insert(
|
|
606
642
|
"createRoot".into(),
|
|
@@ -610,7 +646,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
610
646
|
"render".into(),
|
|
611
647
|
Value::native(|_args: &[Value]| Value::Null),
|
|
612
648
|
);
|
|
613
|
-
|
|
649
|
+
value_object_from_map(render_obj)
|
|
614
650
|
}),
|
|
615
651
|
);
|
|
616
652
|
g.insert(
|
|
@@ -623,31 +659,22 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
623
659
|
);
|
|
624
660
|
let mut document_obj = ObjectMap::default();
|
|
625
661
|
document_obj.insert("body".into(), Value::Null);
|
|
626
|
-
g.insert(
|
|
627
|
-
"document".into(),
|
|
628
|
-
Value::Object(VmRef::new(document_obj)),
|
|
629
|
-
);
|
|
662
|
+
g.insert("document".into(), value_object_from_map(document_obj));
|
|
630
663
|
|
|
631
664
|
#[cfg(feature = "process")]
|
|
632
665
|
if cap_allows(enabled, "process") {
|
|
633
666
|
let mut process_obj = ObjectMap::default();
|
|
634
667
|
process_obj.insert(
|
|
635
668
|
"exit".into(),
|
|
636
|
-
Value::native(|args: &[Value]|
|
|
637
|
-
tishlang_runtime::process_exit(args)
|
|
638
|
-
}),
|
|
669
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_exit(args)),
|
|
639
670
|
);
|
|
640
671
|
process_obj.insert(
|
|
641
672
|
"cwd".into(),
|
|
642
|
-
Value::native(|args: &[Value]|
|
|
643
|
-
tishlang_runtime::process_cwd(args)
|
|
644
|
-
}),
|
|
673
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_cwd(args)),
|
|
645
674
|
);
|
|
646
675
|
process_obj.insert(
|
|
647
676
|
"exec".into(),
|
|
648
|
-
Value::native(|args: &[Value]|
|
|
649
|
-
tishlang_runtime::process_exec(args)
|
|
650
|
-
}),
|
|
677
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_exec(args)),
|
|
651
678
|
);
|
|
652
679
|
process_obj.insert(
|
|
653
680
|
"argv".into(),
|
|
@@ -657,16 +684,13 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
657
684
|
);
|
|
658
685
|
process_obj.insert(
|
|
659
686
|
"env".into(),
|
|
660
|
-
|
|
687
|
+
value_object_from_map(
|
|
661
688
|
std::env::vars()
|
|
662
689
|
.map(|(k, v)| (Arc::from(k.as_str()), Value::String(v.into())))
|
|
663
690
|
.collect(),
|
|
664
|
-
)
|
|
665
|
-
);
|
|
666
|
-
g.insert(
|
|
667
|
-
"process".into(),
|
|
668
|
-
Value::Object(VmRef::new(process_obj)),
|
|
691
|
+
),
|
|
669
692
|
);
|
|
693
|
+
g.insert("process".into(), value_object_from_map(process_obj));
|
|
670
694
|
}
|
|
671
695
|
|
|
672
696
|
#[cfg(feature = "timers")]
|
|
@@ -699,7 +723,6 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
699
723
|
"fetchAll".into(),
|
|
700
724
|
Value::native(|args: &[Value]| tishlang_runtime::fetch_all_promise(args.to_vec())),
|
|
701
725
|
);
|
|
702
|
-
g.insert("Promise".into(), tishlang_runtime::promise_object());
|
|
703
726
|
g.insert(
|
|
704
727
|
"registerStaticRoute".into(),
|
|
705
728
|
Value::native(|args: &[Value]| {
|
|
@@ -729,12 +752,12 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
729
752
|
Value::Object(ref obj) => {
|
|
730
753
|
let obj_ref = obj.borrow();
|
|
731
754
|
if let Some(Value::Function(on_worker)) =
|
|
732
|
-
obj_ref.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
755
|
+
obj_ref.strings.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
733
756
|
{
|
|
734
757
|
let args_for_init = [Value::Number(0.0)];
|
|
735
758
|
on_worker(&args_for_init)
|
|
736
759
|
} else if let Some(h) =
|
|
737
|
-
obj_ref.get(&std::sync::Arc::from("handler")).cloned()
|
|
760
|
+
obj_ref.strings.get(&std::sync::Arc::from("handler")).cloned()
|
|
738
761
|
{
|
|
739
762
|
h
|
|
740
763
|
} else {
|
|
@@ -752,6 +775,11 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
752
775
|
);
|
|
753
776
|
}
|
|
754
777
|
|
|
778
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
779
|
+
if cap_allows(enabled, "http") || cap_allows(enabled, "promise") {
|
|
780
|
+
g.insert("Promise".into(), tishlang_runtime::promise_object());
|
|
781
|
+
}
|
|
782
|
+
|
|
755
783
|
g
|
|
756
784
|
}
|
|
757
785
|
|
|
@@ -894,10 +922,7 @@ impl Vm {
|
|
|
894
922
|
ls.insert(Arc::clone(name), v);
|
|
895
923
|
} else if i == ri {
|
|
896
924
|
let rest_arr: Vec<Value> = args.iter().skip(ri).cloned().collect();
|
|
897
|
-
ls.insert(
|
|
898
|
-
Arc::clone(name),
|
|
899
|
-
Value::Array(VmRef::new(rest_arr)),
|
|
900
|
-
);
|
|
925
|
+
ls.insert(Arc::clone(name), Value::Array(VmRef::new(rest_arr)));
|
|
901
926
|
}
|
|
902
927
|
}
|
|
903
928
|
} else {
|
|
@@ -1131,7 +1156,7 @@ impl Vm {
|
|
|
1131
1156
|
Value::Function(f) => f.clone(),
|
|
1132
1157
|
Value::Object(o) => {
|
|
1133
1158
|
if let Some(Value::Function(call_fn)) =
|
|
1134
|
-
o.borrow().get(
|
|
1159
|
+
o.borrow().strings.get("__call")
|
|
1135
1160
|
{
|
|
1136
1161
|
call_fn.clone()
|
|
1137
1162
|
} else {
|
|
@@ -1170,7 +1195,7 @@ impl Vm {
|
|
|
1170
1195
|
Value::Function(f) => f.clone(),
|
|
1171
1196
|
Value::Object(o) => {
|
|
1172
1197
|
if let Some(Value::Function(call_fn)) =
|
|
1173
|
-
o.borrow().get(
|
|
1198
|
+
o.borrow().strings.get("__call")
|
|
1174
1199
|
{
|
|
1175
1200
|
call_fn.clone()
|
|
1176
1201
|
} else {
|
|
@@ -1376,7 +1401,7 @@ impl Vm {
|
|
|
1376
1401
|
let key = key_val.to_display_string().into();
|
|
1377
1402
|
map.insert(key, val);
|
|
1378
1403
|
}
|
|
1379
|
-
self.stack.push(
|
|
1404
|
+
self.stack.push(value_object_from_map(map));
|
|
1380
1405
|
}
|
|
1381
1406
|
Opcode::EnterTry => {
|
|
1382
1407
|
let offset = Self::read_u16(code, &mut ip) as usize;
|
|
@@ -1427,31 +1452,19 @@ impl Vm {
|
|
|
1427
1452
|
.stack
|
|
1428
1453
|
.pop()
|
|
1429
1454
|
.ok_or_else(|| "Stack underflow".to_string())?;
|
|
1430
|
-
|
|
1431
|
-
(Value::Object(l), Value::Object(r)) =>
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
));
|
|
1442
|
-
}
|
|
1443
|
-
if let Value::Object(r) = &right {
|
|
1444
|
-
for (k, v) in r.borrow().iter() {
|
|
1445
|
-
merged.insert(Arc::clone(k), v.clone());
|
|
1455
|
+
match (&left, &right) {
|
|
1456
|
+
(Value::Object(l), Value::Object(r)) => {
|
|
1457
|
+
let merged = merge_object_data(l, r);
|
|
1458
|
+
self.stack.push(Value::Object(VmRef::new(merged)));
|
|
1459
|
+
}
|
|
1460
|
+
_ => {
|
|
1461
|
+
return Err(format!(
|
|
1462
|
+
"MergeObject: expected two objects, got {} and {}",
|
|
1463
|
+
left.to_display_string(),
|
|
1464
|
+
right.to_display_string()
|
|
1465
|
+
));
|
|
1446
1466
|
}
|
|
1447
|
-
} else {
|
|
1448
|
-
return Err(format!(
|
|
1449
|
-
"MergeObject: right must be object, got {}",
|
|
1450
|
-
right.to_display_string()
|
|
1451
|
-
));
|
|
1452
1467
|
}
|
|
1453
|
-
self.stack
|
|
1454
|
-
.push(Value::Object(VmRef::new(merged)));
|
|
1455
1468
|
}
|
|
1456
1469
|
Opcode::ArraySortNumeric => {
|
|
1457
1470
|
let operand = Self::read_u16(code, &mut ip);
|
|
@@ -1593,20 +1606,25 @@ impl Vm {
|
|
|
1593
1606
|
.stack
|
|
1594
1607
|
.pop()
|
|
1595
1608
|
.ok_or_else(|| "Stack underflow in AwaitPromise".to_string())?;
|
|
1596
|
-
#[cfg(feature = "http")]
|
|
1609
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
1597
1610
|
{
|
|
1598
1611
|
use tishlang_core::Value as V;
|
|
1599
1612
|
match v {
|
|
1600
1613
|
V::Promise(p) => match p.block_until_settled() {
|
|
1601
1614
|
Ok(val) => self.stack.push(val),
|
|
1602
1615
|
Err(rej) => {
|
|
1603
|
-
Self::unwind_throw(
|
|
1616
|
+
Self::unwind_throw(
|
|
1617
|
+
&mut try_handlers,
|
|
1618
|
+
&mut self.stack,
|
|
1619
|
+
&mut ip,
|
|
1620
|
+
rej,
|
|
1621
|
+
)?;
|
|
1604
1622
|
}
|
|
1605
1623
|
},
|
|
1606
1624
|
other => self.stack.push(tishlang_runtime::await_promise(other)),
|
|
1607
1625
|
}
|
|
1608
1626
|
}
|
|
1609
|
-
#[cfg(not(feature = "http"))]
|
|
1627
|
+
#[cfg(not(any(feature = "http", feature = "promise")))]
|
|
1610
1628
|
{
|
|
1611
1629
|
self.stack.push(v);
|
|
1612
1630
|
}
|
|
@@ -1753,26 +1771,24 @@ fn eval_binop(op: BinOp, l: &Value, r: &Value) -> Result<Value, String> {
|
|
|
1753
1771
|
BitXor => Ok(Number((ln as i32 ^ rn as i32) as f64)),
|
|
1754
1772
|
Shl => Ok(Number(((ln as i32) << (rn as i32)) as f64)),
|
|
1755
1773
|
Shr => Ok(Number(((ln as i32) >> (rn as i32)) as f64)),
|
|
1756
|
-
In => {
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
false
|
|
1771
|
-
}
|
|
1774
|
+
In => Ok(Bool(match r {
|
|
1775
|
+
Value::Object(_) => object_has(r, l),
|
|
1776
|
+
Value::Array(a) => {
|
|
1777
|
+
let key_s: Arc<str> = match l {
|
|
1778
|
+
Value::String(s) => Arc::clone(s),
|
|
1779
|
+
Value::Number(n) => n.to_string().into(),
|
|
1780
|
+
_ => l.to_display_string().into(),
|
|
1781
|
+
};
|
|
1782
|
+
if key_s.as_ref() == "length" {
|
|
1783
|
+
true
|
|
1784
|
+
} else if let Ok(idx) = key_s.parse::<usize>() {
|
|
1785
|
+
idx < a.borrow().len()
|
|
1786
|
+
} else {
|
|
1787
|
+
false
|
|
1772
1788
|
}
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
}
|
|
1789
|
+
}
|
|
1790
|
+
_ => false,
|
|
1791
|
+
})),
|
|
1776
1792
|
}
|
|
1777
1793
|
}
|
|
1778
1794
|
|
|
@@ -1792,7 +1808,8 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
1792
1808
|
match obj {
|
|
1793
1809
|
Value::Object(m) => {
|
|
1794
1810
|
let map = m.borrow();
|
|
1795
|
-
map.
|
|
1811
|
+
map.strings
|
|
1812
|
+
.get(key.as_ref())
|
|
1796
1813
|
.cloned()
|
|
1797
1814
|
.ok_or_else(|| format!("Property '{}' not found", key))
|
|
1798
1815
|
}
|
|
@@ -2019,7 +2036,7 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
2019
2036
|
};
|
|
2020
2037
|
Ok(Value::Function(method))
|
|
2021
2038
|
}
|
|
2022
|
-
#[cfg(feature = "http")]
|
|
2039
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
2023
2040
|
Value::Promise(p) => match key.as_ref() {
|
|
2024
2041
|
"then" => {
|
|
2025
2042
|
let pc = Arc::clone(p);
|
|
@@ -2046,7 +2063,7 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
2046
2063
|
fn set_member(obj: &Value, key: &Arc<str>, val: Value) -> Result<(), String> {
|
|
2047
2064
|
match obj {
|
|
2048
2065
|
Value::Object(m) => {
|
|
2049
|
-
m.borrow_mut().insert(Arc::clone(key), val);
|
|
2066
|
+
m.borrow_mut().strings.insert(Arc::clone(key), val);
|
|
2050
2067
|
Ok(())
|
|
2051
2068
|
}
|
|
2052
2069
|
Value::Array(a) => {
|
|
@@ -2065,13 +2082,101 @@ fn set_member(obj: &Value, key: &Arc<str>, val: Value) -> Result<(), String> {
|
|
|
2065
2082
|
}
|
|
2066
2083
|
|
|
2067
2084
|
fn get_index(obj: &Value, idx: &Value) -> Result<Value, String> {
|
|
2068
|
-
|
|
2069
|
-
|
|
2085
|
+
match obj {
|
|
2086
|
+
Value::Array(a) => {
|
|
2087
|
+
let i = match idx {
|
|
2088
|
+
Value::Number(n) => *n as usize,
|
|
2089
|
+
_ => {
|
|
2090
|
+
return Err(format!(
|
|
2091
|
+
"Array index must be number, got {}",
|
|
2092
|
+
idx.type_name()
|
|
2093
|
+
));
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
Ok(a
|
|
2097
|
+
.borrow()
|
|
2098
|
+
.get(i)
|
|
2099
|
+
.cloned()
|
|
2100
|
+
.unwrap_or(Value::Null))
|
|
2101
|
+
}
|
|
2102
|
+
Value::String(s) => {
|
|
2103
|
+
let i = match idx {
|
|
2104
|
+
Value::Number(n) => {
|
|
2105
|
+
let n = *n;
|
|
2106
|
+
if n < 0.0 || n.fract() != 0.0 {
|
|
2107
|
+
return Err(format!(
|
|
2108
|
+
"String index must be non-negative integer, got {}",
|
|
2109
|
+
n
|
|
2110
|
+
));
|
|
2111
|
+
}
|
|
2112
|
+
let i = n as usize;
|
|
2113
|
+
let len = s.chars().count();
|
|
2114
|
+
if i >= len {
|
|
2115
|
+
return Err("Index out of bounds".to_string());
|
|
2116
|
+
}
|
|
2117
|
+
i
|
|
2118
|
+
}
|
|
2119
|
+
_ => {
|
|
2120
|
+
return Err(format!(
|
|
2121
|
+
"String index must be number, got {}",
|
|
2122
|
+
idx.type_name()
|
|
2123
|
+
));
|
|
2124
|
+
}
|
|
2125
|
+
};
|
|
2126
|
+
match s.chars().nth(i) {
|
|
2127
|
+
Some(c) => Ok(Value::String(Arc::from(c.to_string()))),
|
|
2128
|
+
None => Err("Index out of bounds".to_string()),
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
Value::Object(_) => object_get(obj, idx).ok_or_else(|| {
|
|
2132
|
+
format!(
|
|
2133
|
+
"Property '{}' not found",
|
|
2134
|
+
idx.to_display_string()
|
|
2135
|
+
)
|
|
2136
|
+
}),
|
|
2137
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
2138
|
+
Value::Promise(_) => {
|
|
2139
|
+
let key_arc: std::sync::Arc<str> = match idx {
|
|
2140
|
+
Value::String(s) => std::sync::Arc::clone(s),
|
|
2141
|
+
_ => {
|
|
2142
|
+
return Err(format!(
|
|
2143
|
+
"Promise bracket access requires a string key, got {}",
|
|
2144
|
+
idx.type_name()
|
|
2145
|
+
));
|
|
2146
|
+
}
|
|
2147
|
+
};
|
|
2148
|
+
get_member(obj, &key_arc)
|
|
2149
|
+
},
|
|
2150
|
+
_ => Err(format!(
|
|
2151
|
+
"Cannot read property '{}' of {}",
|
|
2152
|
+
idx.to_display_string(),
|
|
2153
|
+
obj.type_name()
|
|
2154
|
+
)),
|
|
2155
|
+
}
|
|
2070
2156
|
}
|
|
2071
2157
|
|
|
2072
2158
|
fn set_index(obj: &Value, idx: &Value, val: Value) -> Result<(), String> {
|
|
2073
|
-
|
|
2074
|
-
|
|
2159
|
+
match obj {
|
|
2160
|
+
Value::Array(a) => {
|
|
2161
|
+
let i = match idx {
|
|
2162
|
+
Value::Number(n) => *n as usize,
|
|
2163
|
+
_ => {
|
|
2164
|
+
return Err(format!(
|
|
2165
|
+
"Array index must be number, got {}",
|
|
2166
|
+
idx.type_name()
|
|
2167
|
+
));
|
|
2168
|
+
}
|
|
2169
|
+
};
|
|
2170
|
+
let mut arr = a.borrow_mut();
|
|
2171
|
+
while arr.len() <= i {
|
|
2172
|
+
arr.push(Value::Null);
|
|
2173
|
+
}
|
|
2174
|
+
arr[i] = val;
|
|
2175
|
+
Ok(())
|
|
2176
|
+
}
|
|
2177
|
+
Value::Object(_) => object_set(obj, idx, val),
|
|
2178
|
+
_ => Err(format!("Cannot set property of {}", obj.type_name())),
|
|
2179
|
+
}
|
|
2075
2180
|
}
|
|
2076
2181
|
|
|
2077
2182
|
/// Run a chunk with every capability linked into this `tishlang_vm` build (tests, embedders).
|