@tishlang/tish 1.9.2 → 1.10.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/main.rs +11 -8
- 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 +43 -15
- 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/object.rs +10 -10
- package/crates/tish_builtins/src/string.rs +1 -3
- package/crates/tish_builtins/src/symbol.rs +83 -0
- package/crates/tish_compile/src/codegen.rs +123 -138
- package/crates/tish_compile/src/lib.rs +25 -3
- package/crates/tish_compile/src/resolve.rs +6 -3
- 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 +192 -4
- 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 +187 -10
- package/crates/tish_native/src/lib.rs +92 -8
- 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 +26 -43
- 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/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 +2 -2
- package/crates/tish_ui/src/runtime/hooks.rs +5 -15
- package/crates/tish_ui/src/runtime/mod.rs +16 -17
- package/crates/tish_vm/Cargo.toml +2 -0
- package/crates/tish_vm/src/vm.rs +218 -153
- package/crates/tish_wasm/src/lib.rs +33 -7
- package/crates/tish_wasm_runtime/Cargo.toml +4 -1
- package/crates/tish_wasm_runtime/src/lib.rs +2 -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(
|
|
@@ -435,7 +457,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
435
457
|
);
|
|
436
458
|
math.insert("PI".into(), Value::Number(std::f64::consts::PI));
|
|
437
459
|
math.insert("E".into(), Value::Number(std::f64::consts::E));
|
|
438
|
-
g.insert("Math".into(),
|
|
460
|
+
g.insert("Math".into(), value_object_from_map(math));
|
|
439
461
|
|
|
440
462
|
let mut json = ObjectMap::default();
|
|
441
463
|
json.insert(
|
|
@@ -455,7 +477,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
455
477
|
Value::String(tishlang_core::json_stringify(v).into())
|
|
456
478
|
}),
|
|
457
479
|
);
|
|
458
|
-
g.insert("JSON".into(),
|
|
480
|
+
g.insert("JSON".into(), value_object_from_map(json));
|
|
459
481
|
|
|
460
482
|
g.insert(
|
|
461
483
|
"parseInt".into(),
|
|
@@ -463,9 +485,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
463
485
|
);
|
|
464
486
|
g.insert(
|
|
465
487
|
"parseFloat".into(),
|
|
466
|
-
Value::native(|args: &[Value]|
|
|
467
|
-
globals_builtins::parse_float(args)
|
|
468
|
-
}),
|
|
488
|
+
Value::native(|args: &[Value]| globals_builtins::parse_float(args)),
|
|
469
489
|
);
|
|
470
490
|
g.insert(
|
|
471
491
|
"encodeURI".into(),
|
|
@@ -502,6 +522,10 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
502
522
|
Value::String(v.type_name().into())
|
|
503
523
|
}),
|
|
504
524
|
);
|
|
525
|
+
g.insert(
|
|
526
|
+
"Symbol".into(),
|
|
527
|
+
tishlang_builtins::symbol::symbol_object(),
|
|
528
|
+
);
|
|
505
529
|
|
|
506
530
|
// Date - at minimum Date.now() for timing
|
|
507
531
|
let mut date = ObjectMap::default();
|
|
@@ -515,7 +539,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
515
539
|
Value::Number(ms)
|
|
516
540
|
}),
|
|
517
541
|
);
|
|
518
|
-
g.insert("Date".into(),
|
|
542
|
+
g.insert("Date".into(), value_object_from_map(date));
|
|
519
543
|
|
|
520
544
|
g.insert(
|
|
521
545
|
"Uint8Array".into(),
|
|
@@ -530,77 +554,49 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
530
554
|
let mut object_methods = ObjectMap::default();
|
|
531
555
|
object_methods.insert(
|
|
532
556
|
"assign".into(),
|
|
533
|
-
Value::native(|args: &[Value]|
|
|
534
|
-
globals_builtins::object_assign(args)
|
|
535
|
-
}),
|
|
557
|
+
Value::native(|args: &[Value]| globals_builtins::object_assign(args)),
|
|
536
558
|
);
|
|
537
559
|
object_methods.insert(
|
|
538
560
|
"fromEntries".into(),
|
|
539
|
-
Value::native(|args: &[Value]|
|
|
540
|
-
globals_builtins::object_from_entries(args)
|
|
541
|
-
}),
|
|
561
|
+
Value::native(|args: &[Value]| globals_builtins::object_from_entries(args)),
|
|
542
562
|
);
|
|
543
563
|
object_methods.insert(
|
|
544
564
|
"keys".into(),
|
|
545
|
-
Value::native(|args: &[Value]|
|
|
546
|
-
globals_builtins::object_keys(args)
|
|
547
|
-
}),
|
|
565
|
+
Value::native(|args: &[Value]| globals_builtins::object_keys(args)),
|
|
548
566
|
);
|
|
549
567
|
object_methods.insert(
|
|
550
568
|
"values".into(),
|
|
551
|
-
Value::native(|args: &[Value]|
|
|
552
|
-
globals_builtins::object_values(args)
|
|
553
|
-
}),
|
|
569
|
+
Value::native(|args: &[Value]| globals_builtins::object_values(args)),
|
|
554
570
|
);
|
|
555
571
|
object_methods.insert(
|
|
556
572
|
"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)),
|
|
573
|
+
Value::native(|args: &[Value]| globals_builtins::object_entries(args)),
|
|
564
574
|
);
|
|
575
|
+
g.insert("Object".into(), value_object_from_map(object_methods));
|
|
565
576
|
|
|
566
577
|
// Array.isArray
|
|
567
578
|
let mut array_static = ObjectMap::default();
|
|
568
579
|
array_static.insert(
|
|
569
580
|
"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)),
|
|
581
|
+
Value::native(|args: &[Value]| globals_builtins::array_is_array(args)),
|
|
577
582
|
);
|
|
583
|
+
g.insert("Array".into(), value_object_from_map(array_static));
|
|
578
584
|
|
|
579
585
|
// String(value) as callable + String.fromCharCode
|
|
580
|
-
let string_convert_fn = Value::native(|args: &[Value]|
|
|
581
|
-
globals_builtins::string_convert(args)
|
|
582
|
-
});
|
|
586
|
+
let string_convert_fn = Value::native(|args: &[Value]| globals_builtins::string_convert(args));
|
|
583
587
|
let mut string_static = ObjectMap::default();
|
|
584
588
|
string_static.insert(
|
|
585
589
|
"fromCharCode".into(),
|
|
586
|
-
Value::native(|args: &[Value]|
|
|
587
|
-
globals_builtins::string_from_char_code(args)
|
|
588
|
-
}),
|
|
590
|
+
Value::native(|args: &[Value]| globals_builtins::string_from_char_code(args)),
|
|
589
591
|
);
|
|
590
592
|
string_static.insert(Arc::from("__call"), string_convert_fn);
|
|
591
|
-
g.insert(
|
|
592
|
-
"String".into(),
|
|
593
|
-
Value::Object(VmRef::new(string_static)),
|
|
594
|
-
);
|
|
593
|
+
g.insert("String".into(), value_object_from_map(string_static));
|
|
595
594
|
|
|
596
595
|
// 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
|
-
);
|
|
596
|
+
g.insert("h".into(), Value::native(|_args: &[Value]| Value::Null));
|
|
601
597
|
g.insert(
|
|
602
598
|
"Fragment".into(),
|
|
603
|
-
|
|
599
|
+
value_object_from_map(ObjectMap::default()),
|
|
604
600
|
);
|
|
605
601
|
g.insert(
|
|
606
602
|
"createRoot".into(),
|
|
@@ -610,7 +606,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
610
606
|
"render".into(),
|
|
611
607
|
Value::native(|_args: &[Value]| Value::Null),
|
|
612
608
|
);
|
|
613
|
-
|
|
609
|
+
value_object_from_map(render_obj)
|
|
614
610
|
}),
|
|
615
611
|
);
|
|
616
612
|
g.insert(
|
|
@@ -623,31 +619,22 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
623
619
|
);
|
|
624
620
|
let mut document_obj = ObjectMap::default();
|
|
625
621
|
document_obj.insert("body".into(), Value::Null);
|
|
626
|
-
g.insert(
|
|
627
|
-
"document".into(),
|
|
628
|
-
Value::Object(VmRef::new(document_obj)),
|
|
629
|
-
);
|
|
622
|
+
g.insert("document".into(), value_object_from_map(document_obj));
|
|
630
623
|
|
|
631
624
|
#[cfg(feature = "process")]
|
|
632
625
|
if cap_allows(enabled, "process") {
|
|
633
626
|
let mut process_obj = ObjectMap::default();
|
|
634
627
|
process_obj.insert(
|
|
635
628
|
"exit".into(),
|
|
636
|
-
Value::native(|args: &[Value]|
|
|
637
|
-
tishlang_runtime::process_exit(args)
|
|
638
|
-
}),
|
|
629
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_exit(args)),
|
|
639
630
|
);
|
|
640
631
|
process_obj.insert(
|
|
641
632
|
"cwd".into(),
|
|
642
|
-
Value::native(|args: &[Value]|
|
|
643
|
-
tishlang_runtime::process_cwd(args)
|
|
644
|
-
}),
|
|
633
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_cwd(args)),
|
|
645
634
|
);
|
|
646
635
|
process_obj.insert(
|
|
647
636
|
"exec".into(),
|
|
648
|
-
Value::native(|args: &[Value]|
|
|
649
|
-
tishlang_runtime::process_exec(args)
|
|
650
|
-
}),
|
|
637
|
+
Value::native(|args: &[Value]| tishlang_runtime::process_exec(args)),
|
|
651
638
|
);
|
|
652
639
|
process_obj.insert(
|
|
653
640
|
"argv".into(),
|
|
@@ -657,16 +644,13 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
657
644
|
);
|
|
658
645
|
process_obj.insert(
|
|
659
646
|
"env".into(),
|
|
660
|
-
|
|
647
|
+
value_object_from_map(
|
|
661
648
|
std::env::vars()
|
|
662
649
|
.map(|(k, v)| (Arc::from(k.as_str()), Value::String(v.into())))
|
|
663
650
|
.collect(),
|
|
664
|
-
)
|
|
665
|
-
);
|
|
666
|
-
g.insert(
|
|
667
|
-
"process".into(),
|
|
668
|
-
Value::Object(VmRef::new(process_obj)),
|
|
651
|
+
),
|
|
669
652
|
);
|
|
653
|
+
g.insert("process".into(), value_object_from_map(process_obj));
|
|
670
654
|
}
|
|
671
655
|
|
|
672
656
|
#[cfg(feature = "timers")]
|
|
@@ -699,7 +683,6 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
699
683
|
"fetchAll".into(),
|
|
700
684
|
Value::native(|args: &[Value]| tishlang_runtime::fetch_all_promise(args.to_vec())),
|
|
701
685
|
);
|
|
702
|
-
g.insert("Promise".into(), tishlang_runtime::promise_object());
|
|
703
686
|
g.insert(
|
|
704
687
|
"registerStaticRoute".into(),
|
|
705
688
|
Value::native(|args: &[Value]| {
|
|
@@ -729,12 +712,12 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
729
712
|
Value::Object(ref obj) => {
|
|
730
713
|
let obj_ref = obj.borrow();
|
|
731
714
|
if let Some(Value::Function(on_worker)) =
|
|
732
|
-
obj_ref.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
715
|
+
obj_ref.strings.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
733
716
|
{
|
|
734
717
|
let args_for_init = [Value::Number(0.0)];
|
|
735
718
|
on_worker(&args_for_init)
|
|
736
719
|
} else if let Some(h) =
|
|
737
|
-
obj_ref.get(&std::sync::Arc::from("handler")).cloned()
|
|
720
|
+
obj_ref.strings.get(&std::sync::Arc::from("handler")).cloned()
|
|
738
721
|
{
|
|
739
722
|
h
|
|
740
723
|
} else {
|
|
@@ -752,6 +735,11 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
752
735
|
);
|
|
753
736
|
}
|
|
754
737
|
|
|
738
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
739
|
+
if cap_allows(enabled, "http") || cap_allows(enabled, "promise") {
|
|
740
|
+
g.insert("Promise".into(), tishlang_runtime::promise_object());
|
|
741
|
+
}
|
|
742
|
+
|
|
755
743
|
g
|
|
756
744
|
}
|
|
757
745
|
|
|
@@ -894,10 +882,7 @@ impl Vm {
|
|
|
894
882
|
ls.insert(Arc::clone(name), v);
|
|
895
883
|
} else if i == ri {
|
|
896
884
|
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
|
-
);
|
|
885
|
+
ls.insert(Arc::clone(name), Value::Array(VmRef::new(rest_arr)));
|
|
901
886
|
}
|
|
902
887
|
}
|
|
903
888
|
} else {
|
|
@@ -1131,7 +1116,7 @@ impl Vm {
|
|
|
1131
1116
|
Value::Function(f) => f.clone(),
|
|
1132
1117
|
Value::Object(o) => {
|
|
1133
1118
|
if let Some(Value::Function(call_fn)) =
|
|
1134
|
-
o.borrow().get(
|
|
1119
|
+
o.borrow().strings.get("__call")
|
|
1135
1120
|
{
|
|
1136
1121
|
call_fn.clone()
|
|
1137
1122
|
} else {
|
|
@@ -1170,7 +1155,7 @@ impl Vm {
|
|
|
1170
1155
|
Value::Function(f) => f.clone(),
|
|
1171
1156
|
Value::Object(o) => {
|
|
1172
1157
|
if let Some(Value::Function(call_fn)) =
|
|
1173
|
-
o.borrow().get(
|
|
1158
|
+
o.borrow().strings.get("__call")
|
|
1174
1159
|
{
|
|
1175
1160
|
call_fn.clone()
|
|
1176
1161
|
} else {
|
|
@@ -1376,7 +1361,7 @@ impl Vm {
|
|
|
1376
1361
|
let key = key_val.to_display_string().into();
|
|
1377
1362
|
map.insert(key, val);
|
|
1378
1363
|
}
|
|
1379
|
-
self.stack.push(
|
|
1364
|
+
self.stack.push(value_object_from_map(map));
|
|
1380
1365
|
}
|
|
1381
1366
|
Opcode::EnterTry => {
|
|
1382
1367
|
let offset = Self::read_u16(code, &mut ip) as usize;
|
|
@@ -1427,31 +1412,19 @@ impl Vm {
|
|
|
1427
1412
|
.stack
|
|
1428
1413
|
.pop()
|
|
1429
1414
|
.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());
|
|
1415
|
+
match (&left, &right) {
|
|
1416
|
+
(Value::Object(l), Value::Object(r)) => {
|
|
1417
|
+
let merged = merge_object_data(l, r);
|
|
1418
|
+
self.stack.push(Value::Object(VmRef::new(merged)));
|
|
1419
|
+
}
|
|
1420
|
+
_ => {
|
|
1421
|
+
return Err(format!(
|
|
1422
|
+
"MergeObject: expected two objects, got {} and {}",
|
|
1423
|
+
left.to_display_string(),
|
|
1424
|
+
right.to_display_string()
|
|
1425
|
+
));
|
|
1446
1426
|
}
|
|
1447
|
-
} else {
|
|
1448
|
-
return Err(format!(
|
|
1449
|
-
"MergeObject: right must be object, got {}",
|
|
1450
|
-
right.to_display_string()
|
|
1451
|
-
));
|
|
1452
1427
|
}
|
|
1453
|
-
self.stack
|
|
1454
|
-
.push(Value::Object(VmRef::new(merged)));
|
|
1455
1428
|
}
|
|
1456
1429
|
Opcode::ArraySortNumeric => {
|
|
1457
1430
|
let operand = Self::read_u16(code, &mut ip);
|
|
@@ -1593,20 +1566,25 @@ impl Vm {
|
|
|
1593
1566
|
.stack
|
|
1594
1567
|
.pop()
|
|
1595
1568
|
.ok_or_else(|| "Stack underflow in AwaitPromise".to_string())?;
|
|
1596
|
-
#[cfg(feature = "http")]
|
|
1569
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
1597
1570
|
{
|
|
1598
1571
|
use tishlang_core::Value as V;
|
|
1599
1572
|
match v {
|
|
1600
1573
|
V::Promise(p) => match p.block_until_settled() {
|
|
1601
1574
|
Ok(val) => self.stack.push(val),
|
|
1602
1575
|
Err(rej) => {
|
|
1603
|
-
Self::unwind_throw(
|
|
1576
|
+
Self::unwind_throw(
|
|
1577
|
+
&mut try_handlers,
|
|
1578
|
+
&mut self.stack,
|
|
1579
|
+
&mut ip,
|
|
1580
|
+
rej,
|
|
1581
|
+
)?;
|
|
1604
1582
|
}
|
|
1605
1583
|
},
|
|
1606
1584
|
other => self.stack.push(tishlang_runtime::await_promise(other)),
|
|
1607
1585
|
}
|
|
1608
1586
|
}
|
|
1609
|
-
#[cfg(not(feature = "http"))]
|
|
1587
|
+
#[cfg(not(any(feature = "http", feature = "promise")))]
|
|
1610
1588
|
{
|
|
1611
1589
|
self.stack.push(v);
|
|
1612
1590
|
}
|
|
@@ -1753,26 +1731,24 @@ fn eval_binop(op: BinOp, l: &Value, r: &Value) -> Result<Value, String> {
|
|
|
1753
1731
|
BitXor => Ok(Number((ln as i32 ^ rn as i32) as f64)),
|
|
1754
1732
|
Shl => Ok(Number(((ln as i32) << (rn as i32)) as f64)),
|
|
1755
1733
|
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
|
-
}
|
|
1734
|
+
In => Ok(Bool(match r {
|
|
1735
|
+
Value::Object(_) => object_has(r, l),
|
|
1736
|
+
Value::Array(a) => {
|
|
1737
|
+
let key_s: Arc<str> = match l {
|
|
1738
|
+
Value::String(s) => Arc::clone(s),
|
|
1739
|
+
Value::Number(n) => n.to_string().into(),
|
|
1740
|
+
_ => l.to_display_string().into(),
|
|
1741
|
+
};
|
|
1742
|
+
if key_s.as_ref() == "length" {
|
|
1743
|
+
true
|
|
1744
|
+
} else if let Ok(idx) = key_s.parse::<usize>() {
|
|
1745
|
+
idx < a.borrow().len()
|
|
1746
|
+
} else {
|
|
1747
|
+
false
|
|
1772
1748
|
}
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
}
|
|
1749
|
+
}
|
|
1750
|
+
_ => false,
|
|
1751
|
+
})),
|
|
1776
1752
|
}
|
|
1777
1753
|
}
|
|
1778
1754
|
|
|
@@ -1792,7 +1768,8 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
1792
1768
|
match obj {
|
|
1793
1769
|
Value::Object(m) => {
|
|
1794
1770
|
let map = m.borrow();
|
|
1795
|
-
map.
|
|
1771
|
+
map.strings
|
|
1772
|
+
.get(key.as_ref())
|
|
1796
1773
|
.cloned()
|
|
1797
1774
|
.ok_or_else(|| format!("Property '{}' not found", key))
|
|
1798
1775
|
}
|
|
@@ -2019,7 +1996,7 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
2019
1996
|
};
|
|
2020
1997
|
Ok(Value::Function(method))
|
|
2021
1998
|
}
|
|
2022
|
-
#[cfg(feature = "http")]
|
|
1999
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
2023
2000
|
Value::Promise(p) => match key.as_ref() {
|
|
2024
2001
|
"then" => {
|
|
2025
2002
|
let pc = Arc::clone(p);
|
|
@@ -2046,7 +2023,7 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
2046
2023
|
fn set_member(obj: &Value, key: &Arc<str>, val: Value) -> Result<(), String> {
|
|
2047
2024
|
match obj {
|
|
2048
2025
|
Value::Object(m) => {
|
|
2049
|
-
m.borrow_mut().insert(Arc::clone(key), val);
|
|
2026
|
+
m.borrow_mut().strings.insert(Arc::clone(key), val);
|
|
2050
2027
|
Ok(())
|
|
2051
2028
|
}
|
|
2052
2029
|
Value::Array(a) => {
|
|
@@ -2065,13 +2042,101 @@ fn set_member(obj: &Value, key: &Arc<str>, val: Value) -> Result<(), String> {
|
|
|
2065
2042
|
}
|
|
2066
2043
|
|
|
2067
2044
|
fn get_index(obj: &Value, idx: &Value) -> Result<Value, String> {
|
|
2068
|
-
|
|
2069
|
-
|
|
2045
|
+
match obj {
|
|
2046
|
+
Value::Array(a) => {
|
|
2047
|
+
let i = match idx {
|
|
2048
|
+
Value::Number(n) => *n as usize,
|
|
2049
|
+
_ => {
|
|
2050
|
+
return Err(format!(
|
|
2051
|
+
"Array index must be number, got {}",
|
|
2052
|
+
idx.type_name()
|
|
2053
|
+
));
|
|
2054
|
+
}
|
|
2055
|
+
};
|
|
2056
|
+
Ok(a
|
|
2057
|
+
.borrow()
|
|
2058
|
+
.get(i)
|
|
2059
|
+
.cloned()
|
|
2060
|
+
.unwrap_or(Value::Null))
|
|
2061
|
+
}
|
|
2062
|
+
Value::String(s) => {
|
|
2063
|
+
let i = match idx {
|
|
2064
|
+
Value::Number(n) => {
|
|
2065
|
+
let n = *n;
|
|
2066
|
+
if n < 0.0 || n.fract() != 0.0 {
|
|
2067
|
+
return Err(format!(
|
|
2068
|
+
"String index must be non-negative integer, got {}",
|
|
2069
|
+
n
|
|
2070
|
+
));
|
|
2071
|
+
}
|
|
2072
|
+
let i = n as usize;
|
|
2073
|
+
let len = s.chars().count();
|
|
2074
|
+
if i >= len {
|
|
2075
|
+
return Err("Index out of bounds".to_string());
|
|
2076
|
+
}
|
|
2077
|
+
i
|
|
2078
|
+
}
|
|
2079
|
+
_ => {
|
|
2080
|
+
return Err(format!(
|
|
2081
|
+
"String index must be number, got {}",
|
|
2082
|
+
idx.type_name()
|
|
2083
|
+
));
|
|
2084
|
+
}
|
|
2085
|
+
};
|
|
2086
|
+
match s.chars().nth(i) {
|
|
2087
|
+
Some(c) => Ok(Value::String(Arc::from(c.to_string()))),
|
|
2088
|
+
None => Err("Index out of bounds".to_string()),
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
Value::Object(_) => object_get(obj, idx).ok_or_else(|| {
|
|
2092
|
+
format!(
|
|
2093
|
+
"Property '{}' not found",
|
|
2094
|
+
idx.to_display_string()
|
|
2095
|
+
)
|
|
2096
|
+
}),
|
|
2097
|
+
#[cfg(any(feature = "http", feature = "promise"))]
|
|
2098
|
+
Value::Promise(_) => {
|
|
2099
|
+
let key_arc: std::sync::Arc<str> = match idx {
|
|
2100
|
+
Value::String(s) => std::sync::Arc::clone(s),
|
|
2101
|
+
_ => {
|
|
2102
|
+
return Err(format!(
|
|
2103
|
+
"Promise bracket access requires a string key, got {}",
|
|
2104
|
+
idx.type_name()
|
|
2105
|
+
));
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
get_member(obj, &key_arc)
|
|
2109
|
+
},
|
|
2110
|
+
_ => Err(format!(
|
|
2111
|
+
"Cannot read property '{}' of {}",
|
|
2112
|
+
idx.to_display_string(),
|
|
2113
|
+
obj.type_name()
|
|
2114
|
+
)),
|
|
2115
|
+
}
|
|
2070
2116
|
}
|
|
2071
2117
|
|
|
2072
2118
|
fn set_index(obj: &Value, idx: &Value, val: Value) -> Result<(), String> {
|
|
2073
|
-
|
|
2074
|
-
|
|
2119
|
+
match obj {
|
|
2120
|
+
Value::Array(a) => {
|
|
2121
|
+
let i = match idx {
|
|
2122
|
+
Value::Number(n) => *n as usize,
|
|
2123
|
+
_ => {
|
|
2124
|
+
return Err(format!(
|
|
2125
|
+
"Array index must be number, got {}",
|
|
2126
|
+
idx.type_name()
|
|
2127
|
+
));
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
let mut arr = a.borrow_mut();
|
|
2131
|
+
while arr.len() <= i {
|
|
2132
|
+
arr.push(Value::Null);
|
|
2133
|
+
}
|
|
2134
|
+
arr[i] = val;
|
|
2135
|
+
Ok(())
|
|
2136
|
+
}
|
|
2137
|
+
Value::Object(_) => object_set(obj, idx, val),
|
|
2138
|
+
_ => Err(format!("Cannot set property of {}", obj.type_name())),
|
|
2139
|
+
}
|
|
2075
2140
|
}
|
|
2076
2141
|
|
|
2077
2142
|
/// Run a chunk with every capability linked into this `tishlang_vm` build (tests, embedders).
|