@tishlang/tish 1.7.0 → 1.9.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 +2 -0
- package/README.md +2 -0
- package/bin/tish +0 -0
- package/crates/js_to_tish/src/transform/expr.rs +28 -8
- package/crates/js_to_tish/src/transform/stmt.rs +49 -22
- package/crates/tish/Cargo.toml +14 -5
- package/crates/tish/src/cargo_native_registry.rs +29 -0
- package/crates/tish/src/cli_help.rs +16 -10
- package/crates/tish/src/main.rs +87 -32
- package/crates/tish/src/repl_completion.rs +3 -3
- package/crates/tish/tests/cargo_example_compile.rs +1 -1
- package/crates/tish/tests/integration_test.rs +19 -7
- package/crates/tish/tests/shortcircuit.rs +1 -1
- package/crates/tish_ast/src/ast.rs +80 -9
- package/crates/tish_build_utils/Cargo.toml +4 -0
- package/crates/tish_build_utils/src/lib.rs +105 -2
- package/crates/tish_builtins/Cargo.toml +5 -1
- package/crates/tish_builtins/src/array.rs +13 -12
- package/crates/tish_builtins/src/construct.rs +34 -33
- package/crates/tish_builtins/src/globals.rs +12 -11
- package/crates/tish_builtins/src/helpers.rs +2 -1
- package/crates/tish_builtins/src/object.rs +3 -2
- package/crates/tish_builtins/src/string.rs +73 -3
- package/crates/tish_bytecode/src/compiler.rs +12 -14
- package/crates/tish_bytecode/src/opcode.rs +12 -3
- package/crates/tish_compile/Cargo.toml +1 -0
- package/crates/tish_compile/src/codegen.rs +745 -199
- package/crates/tish_compile/src/infer.rs +6 -0
- package/crates/tish_compile/src/lib.rs +4 -3
- package/crates/tish_compile/src/resolve.rs +180 -82
- package/crates/tish_compile/src/types.rs +175 -11
- package/crates/tish_compile_js/Cargo.toml +1 -0
- package/crates/tish_compile_js/src/codegen.rs +152 -29
- package/crates/tish_compile_js/src/lib.rs +3 -1
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +31 -12
- package/crates/tish_core/Cargo.toml +8 -0
- package/crates/tish_core/src/json.rs +102 -53
- package/crates/tish_core/src/lib.rs +3 -1
- package/crates/tish_core/src/macros.rs +5 -5
- package/crates/tish_core/src/value.rs +53 -15
- package/crates/tish_core/src/vmref.rs +178 -0
- package/crates/tish_eval/Cargo.toml +17 -2
- package/crates/tish_eval/src/eval.rs +90 -28
- package/crates/tish_eval/src/http.rs +61 -0
- package/crates/tish_eval/src/lib.rs +3 -3
- package/crates/tish_eval/src/natives.rs +41 -0
- package/crates/tish_eval/src/value.rs +7 -3
- package/crates/tish_eval/src/value_convert.rs +13 -5
- package/crates/tish_fmt/src/lib.rs +120 -30
- package/crates/tish_lexer/src/lib.rs +20 -5
- package/crates/tish_lexer/src/token.rs +4 -0
- package/crates/tish_llvm/src/lib.rs +3 -1
- package/crates/tish_lsp/Cargo.toml +4 -1
- package/crates/tish_lsp/README.md +1 -1
- package/crates/tish_lsp/src/builtin_goto.rs +261 -0
- package/crates/tish_lsp/src/import_goto.rs +549 -0
- package/crates/tish_lsp/src/main.rs +502 -102
- package/crates/tish_native/src/build.rs +3 -2
- package/crates/tish_native/src/lib.rs +6 -2
- package/crates/tish_opt/src/lib.rs +17 -2
- package/crates/tish_parser/src/lib.rs +10 -3
- package/crates/tish_parser/src/parser.rs +346 -56
- package/crates/tish_pg/Cargo.toml +34 -0
- package/crates/tish_pg/README.md +38 -0
- package/crates/tish_pg/src/error.rs +52 -0
- package/crates/tish_pg/src/lib.rs +967 -0
- package/crates/tish_resolve/Cargo.toml +13 -0
- package/crates/tish_resolve/src/lib.rs +3436 -0
- package/crates/tish_resolve/src/pos.rs +133 -0
- package/crates/tish_runtime/Cargo.toml +68 -3
- package/crates/tish_runtime/src/http.rs +1123 -141
- package/crates/tish_runtime/src/http_fetch.rs +15 -14
- package/crates/tish_runtime/src/http_hyper.rs +418 -0
- package/crates/tish_runtime/src/http_prefork.rs +189 -0
- package/crates/tish_runtime/src/lib.rs +159 -29
- package/crates/tish_runtime/src/promise.rs +199 -36
- package/crates/tish_runtime/src/promise_io.rs +2 -1
- package/crates/tish_runtime/src/timers.rs +37 -1
- package/crates/tish_runtime/src/ws.rs +26 -28
- package/crates/tish_ui/src/jsx.rs +279 -8
- package/crates/tish_ui/src/lib.rs +5 -2
- package/crates/tish_ui/src/runtime/hooks.rs +406 -45
- package/crates/tish_ui/src/runtime/mod.rs +36 -9
- package/crates/tish_vm/Cargo.toml +15 -5
- package/crates/tish_vm/src/vm.rs +506 -259
- package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +3 -1
- package/crates/tish_wasm/src/lib.rs +17 -14
- package/crates/tish_wasm_runtime/Cargo.toml +2 -1
- package/crates/tish_wasm_runtime/src/lib.rs +1 -1
- package/crates/tishlang_cargo_bindgen/Cargo.toml +1 -0
- package/crates/tishlang_cargo_bindgen/src/discover.rs +68 -0
- package/crates/tishlang_cargo_bindgen/src/lib.rs +5 -4
- package/justfile +8 -0
- package/package.json +1 -1
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- package/platform/win32-x64/tish.exe +0 -0
package/crates/tish_vm/src/vm.rs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
//! Stack-based bytecode VM.
|
|
2
2
|
|
|
3
3
|
use std::cell::RefCell;
|
|
4
|
-
use
|
|
4
|
+
use tishlang_core::VmRef;
|
|
5
|
+
use std::collections::{HashMap, HashSet};
|
|
5
6
|
use std::rc::Rc;
|
|
6
7
|
use std::sync::Arc;
|
|
7
8
|
|
|
@@ -12,13 +13,43 @@ use tishlang_builtins::globals as globals_builtins;
|
|
|
12
13
|
use tishlang_builtins::math as math_builtins;
|
|
13
14
|
use tishlang_builtins::string as str_builtins;
|
|
14
15
|
use tishlang_bytecode::{u8_to_binop, u8_to_unaryop, Chunk, Constant, Opcode, NO_REST_PARAM};
|
|
15
|
-
use tishlang_core::{ObjectMap, Value};
|
|
16
|
+
use tishlang_core::{NativeFn, ObjectMap, Value};
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
/// Wrap a closure in the right shared pointer for the current build.
|
|
19
|
+
/// Under `send-values` that's `Arc<dyn Fn + Send + Sync>`; otherwise it's
|
|
20
|
+
/// plain `Rc<dyn Fn>`. Call sites can stay ignorant of the distinction.
|
|
21
|
+
#[cfg(feature = "send-values")]
|
|
22
|
+
#[inline]
|
|
23
|
+
fn make_native_fn<F>(f: F) -> NativeFn
|
|
24
|
+
where
|
|
25
|
+
F: Fn(&[Value]) -> Value + Send + Sync + 'static,
|
|
26
|
+
{
|
|
27
|
+
Arc::new(f)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[cfg(not(feature = "send-values"))]
|
|
31
|
+
#[inline]
|
|
32
|
+
fn make_native_fn<F>(f: F) -> NativeFn
|
|
33
|
+
where
|
|
34
|
+
F: Fn(&[Value]) -> Value + 'static,
|
|
35
|
+
{
|
|
36
|
+
Rc::new(f)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Array / string / object methods have the same shape as `NativeFn`, which
|
|
40
|
+
// is already feature-gated (`Rc<dyn Fn>` vs `Arc<dyn Fn + Send + Sync>`).
|
|
41
|
+
// Alias to that so the VM picks the right pointer type automatically.
|
|
42
|
+
type ArrayMethodFn = NativeFn;
|
|
18
43
|
|
|
19
44
|
/// Feature names enabled for this VM run (`tish run --feature …`). `full` enables every optional capability.
|
|
20
45
|
#[cfg_attr(
|
|
21
|
-
not(any(
|
|
46
|
+
not(any(
|
|
47
|
+
feature = "fs",
|
|
48
|
+
feature = "http",
|
|
49
|
+
feature = "timers",
|
|
50
|
+
feature = "process",
|
|
51
|
+
feature = "ws"
|
|
52
|
+
)),
|
|
22
53
|
allow(dead_code)
|
|
23
54
|
)]
|
|
24
55
|
fn cap_allows(enabled: &HashSet<String>, name: &str) -> bool {
|
|
@@ -31,6 +62,8 @@ pub fn all_compiled_capabilities() -> HashSet<String> {
|
|
|
31
62
|
let mut s = HashSet::new();
|
|
32
63
|
#[cfg(feature = "http")]
|
|
33
64
|
s.insert("http".to_string());
|
|
65
|
+
#[cfg(feature = "timers")]
|
|
66
|
+
s.insert("timers".to_string());
|
|
34
67
|
#[cfg(feature = "fs")]
|
|
35
68
|
s.insert("fs".to_string());
|
|
36
69
|
#[cfg(feature = "process")]
|
|
@@ -44,31 +77,37 @@ pub fn all_compiled_capabilities() -> HashSet<String> {
|
|
|
44
77
|
|
|
45
78
|
/// Look up built-in module export for LoadNativeExport. Returns None if unknown or feature disabled.
|
|
46
79
|
#[cfg_attr(
|
|
47
|
-
not(any(
|
|
80
|
+
not(any(
|
|
81
|
+
feature = "fs",
|
|
82
|
+
feature = "http",
|
|
83
|
+
feature = "timers",
|
|
84
|
+
feature = "process",
|
|
85
|
+
feature = "ws"
|
|
86
|
+
)),
|
|
48
87
|
allow(unused_variables)
|
|
49
88
|
)]
|
|
50
89
|
fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str) -> Option<Value> {
|
|
51
90
|
#[cfg(feature = "fs")]
|
|
52
91
|
if spec == "tish:fs" && cap_allows(enabled, "fs") {
|
|
53
92
|
return match export_name {
|
|
54
|
-
"readFile" => Some(Value::
|
|
93
|
+
"readFile" => Some(Value::native(|args: &[Value]| {
|
|
55
94
|
tishlang_runtime::read_file(args)
|
|
56
|
-
}))
|
|
57
|
-
"writeFile" => Some(Value::
|
|
95
|
+
})),
|
|
96
|
+
"writeFile" => Some(Value::native(|args: &[Value]| {
|
|
58
97
|
tishlang_runtime::write_file(args)
|
|
59
|
-
}))
|
|
60
|
-
"fileExists" => Some(Value::
|
|
98
|
+
})),
|
|
99
|
+
"fileExists" => Some(Value::native(|args: &[Value]| {
|
|
61
100
|
tishlang_runtime::file_exists(args)
|
|
62
|
-
}))
|
|
63
|
-
"isDir" => Some(Value::
|
|
101
|
+
})),
|
|
102
|
+
"isDir" => Some(Value::native(|args: &[Value]| {
|
|
64
103
|
tishlang_runtime::is_dir(args)
|
|
65
|
-
}))
|
|
66
|
-
"readDir" => Some(Value::
|
|
104
|
+
})),
|
|
105
|
+
"readDir" => Some(Value::native(|args: &[Value]| {
|
|
67
106
|
tishlang_runtime::read_dir(args)
|
|
68
|
-
}))
|
|
69
|
-
"mkdir" => Some(Value::
|
|
107
|
+
})),
|
|
108
|
+
"mkdir" => Some(Value::native(|args: &[Value]| {
|
|
70
109
|
tishlang_runtime::mkdir(args)
|
|
71
|
-
}))
|
|
110
|
+
})),
|
|
72
111
|
_ => None,
|
|
73
112
|
};
|
|
74
113
|
}
|
|
@@ -76,81 +115,123 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
|
|
|
76
115
|
if spec == "tish:http" && cap_allows(enabled, "http") {
|
|
77
116
|
return match export_name {
|
|
78
117
|
// Bytecode compiler lowers `await expr` to `tish:http.await(promise)` (see tish_bytecode compiler).
|
|
79
|
-
"await" => Some(Value::
|
|
118
|
+
"await" => Some(Value::native(|args: &[Value]| {
|
|
80
119
|
tishlang_runtime::await_promise(args.first().cloned().unwrap_or(Value::Null))
|
|
81
|
-
}))
|
|
82
|
-
"fetch" => Some(Value::
|
|
120
|
+
})),
|
|
121
|
+
"fetch" => Some(Value::native(|args: &[Value]| {
|
|
83
122
|
tishlang_runtime::fetch_promise(args.to_vec())
|
|
84
|
-
}))
|
|
85
|
-
"fetchAll" => Some(Value::
|
|
123
|
+
})),
|
|
124
|
+
"fetchAll" => Some(Value::native(|args: &[Value]| {
|
|
86
125
|
tishlang_runtime::fetch_all_promise(args.to_vec())
|
|
87
|
-
}))
|
|
88
|
-
"
|
|
89
|
-
|
|
90
|
-
|
|
126
|
+
})),
|
|
127
|
+
"Promise" => Some(tishlang_runtime::promise_object()),
|
|
128
|
+
"serve" => Some(Value::native(|args: &[Value]| {
|
|
129
|
+
// Phase-1 item 2: support `serve(port, { handler, onWorker })`
|
|
130
|
+
// in addition to `serve(port, handler)`. When an options
|
|
131
|
+
// object is given and onWorker is a function, invoke it with
|
|
132
|
+
// worker id 0 and expect it to return the request handler.
|
|
133
|
+
let raw = args.get(1).cloned().unwrap_or(Value::Null);
|
|
134
|
+
let handler_value = match raw {
|
|
135
|
+
Value::Function(_) => raw,
|
|
136
|
+
Value::Object(ref obj) => {
|
|
137
|
+
let obj_ref = obj.borrow();
|
|
138
|
+
if let Some(Value::Function(on_worker)) =
|
|
139
|
+
obj_ref.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
140
|
+
{
|
|
141
|
+
let args_for_init = [Value::Number(0.0)];
|
|
142
|
+
on_worker(&args_for_init)
|
|
143
|
+
} else if let Some(h) =
|
|
144
|
+
obj_ref.get(&std::sync::Arc::from("handler")).cloned()
|
|
145
|
+
{
|
|
146
|
+
h
|
|
147
|
+
} else {
|
|
148
|
+
Value::Null
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
_ => Value::Null,
|
|
152
|
+
};
|
|
153
|
+
if let Value::Function(f) = handler_value {
|
|
91
154
|
tishlang_runtime::http_serve(args, move |req_args| f(req_args))
|
|
92
155
|
} else {
|
|
93
156
|
Value::Null
|
|
94
157
|
}
|
|
95
|
-
}))
|
|
158
|
+
})),
|
|
159
|
+
_ => None,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
#[cfg(feature = "timers")]
|
|
163
|
+
if spec == "tish:timers" && cap_allows(enabled, "timers") {
|
|
164
|
+
return match export_name {
|
|
165
|
+
"setTimeout" => Some(Value::native(|args: &[Value]| {
|
|
166
|
+
tishlang_runtime::timer_set_timeout(args)
|
|
167
|
+
})),
|
|
168
|
+
"setInterval" => Some(Value::native(|args: &[Value]| {
|
|
169
|
+
tishlang_runtime::timer_set_interval(args)
|
|
170
|
+
})),
|
|
171
|
+
"clearTimeout" => Some(Value::native(|args: &[Value]| {
|
|
172
|
+
tishlang_runtime::timer_clear_timeout(args)
|
|
173
|
+
})),
|
|
174
|
+
"clearInterval" => Some(Value::native(|args: &[Value]| {
|
|
175
|
+
tishlang_runtime::timer_clear_interval(args)
|
|
176
|
+
})),
|
|
96
177
|
_ => None,
|
|
97
178
|
};
|
|
98
179
|
}
|
|
99
180
|
#[cfg(feature = "process")]
|
|
100
181
|
if spec == "tish:process" && cap_allows(enabled, "process") {
|
|
101
182
|
return match export_name {
|
|
102
|
-
"exit" => Some(Value::
|
|
183
|
+
"exit" => Some(Value::native(|args: &[Value]| {
|
|
103
184
|
tishlang_runtime::process_exit(args)
|
|
104
|
-
}))
|
|
105
|
-
"cwd" => Some(Value::
|
|
185
|
+
})),
|
|
186
|
+
"cwd" => Some(Value::native(|args: &[Value]| {
|
|
106
187
|
tishlang_runtime::process_cwd(args)
|
|
107
|
-
}))
|
|
108
|
-
"exec" => Some(Value::
|
|
188
|
+
})),
|
|
189
|
+
"exec" => Some(Value::native(|args: &[Value]| {
|
|
109
190
|
tishlang_runtime::process_exec(args)
|
|
110
|
-
}))
|
|
111
|
-
"argv" => Some(Value::Array(
|
|
191
|
+
})),
|
|
192
|
+
"argv" => Some(Value::Array(VmRef::new(
|
|
112
193
|
std::env::args().map(|s| Value::String(s.into())).collect(),
|
|
113
|
-
)))
|
|
114
|
-
"env" => Some(Value::Object(
|
|
194
|
+
))),
|
|
195
|
+
"env" => Some(Value::Object(VmRef::new(
|
|
115
196
|
std::env::vars()
|
|
116
197
|
.map(|(k, v)| (Arc::from(k.as_str()), Value::String(v.into())))
|
|
117
198
|
.collect(),
|
|
118
|
-
)))
|
|
199
|
+
))),
|
|
119
200
|
"process" => {
|
|
120
201
|
let mut m = ObjectMap::default();
|
|
121
202
|
m.insert(
|
|
122
203
|
"exit".into(),
|
|
123
|
-
Value::
|
|
204
|
+
Value::native(|args: &[Value]| {
|
|
124
205
|
tishlang_runtime::process_exit(args)
|
|
125
|
-
})
|
|
206
|
+
}),
|
|
126
207
|
);
|
|
127
208
|
m.insert(
|
|
128
209
|
"cwd".into(),
|
|
129
|
-
Value::
|
|
210
|
+
Value::native(|args: &[Value]| {
|
|
130
211
|
tishlang_runtime::process_cwd(args)
|
|
131
|
-
})
|
|
212
|
+
}),
|
|
132
213
|
);
|
|
133
214
|
m.insert(
|
|
134
215
|
"exec".into(),
|
|
135
|
-
Value::
|
|
216
|
+
Value::native(|args: &[Value]| {
|
|
136
217
|
tishlang_runtime::process_exec(args)
|
|
137
|
-
})
|
|
218
|
+
}),
|
|
138
219
|
);
|
|
139
220
|
m.insert(
|
|
140
221
|
"argv".into(),
|
|
141
|
-
Value::Array(
|
|
222
|
+
Value::Array(VmRef::new(
|
|
142
223
|
std::env::args().map(|s| Value::String(s.into())).collect(),
|
|
143
|
-
))
|
|
224
|
+
)),
|
|
144
225
|
);
|
|
145
226
|
m.insert(
|
|
146
227
|
"env".into(),
|
|
147
|
-
Value::Object(
|
|
228
|
+
Value::Object(VmRef::new(
|
|
148
229
|
std::env::vars()
|
|
149
230
|
.map(|(k, v)| (Arc::from(k.as_str()), Value::String(v.into())))
|
|
150
231
|
.collect(),
|
|
151
|
-
))
|
|
232
|
+
)),
|
|
152
233
|
);
|
|
153
|
-
Some(Value::Object(
|
|
234
|
+
Some(Value::Object(VmRef::new(m)))
|
|
154
235
|
}
|
|
155
236
|
_ => None,
|
|
156
237
|
};
|
|
@@ -158,13 +239,13 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
|
|
|
158
239
|
#[cfg(feature = "ws")]
|
|
159
240
|
if spec == "tish:ws" && cap_allows(enabled, "ws") {
|
|
160
241
|
return match export_name {
|
|
161
|
-
"WebSocket" => Some(Value::
|
|
242
|
+
"WebSocket" => Some(Value::native(|args: &[Value]| {
|
|
162
243
|
tishlang_runtime::web_socket_client(args)
|
|
163
|
-
}))
|
|
164
|
-
"Server" => Some(Value::
|
|
244
|
+
})),
|
|
245
|
+
"Server" => Some(Value::native(|args: &[Value]| {
|
|
165
246
|
tishlang_runtime::web_socket_server_construct(args)
|
|
166
|
-
}))
|
|
167
|
-
"wsSend" => Some(Value::
|
|
247
|
+
})),
|
|
248
|
+
"wsSend" => Some(Value::native(|args: &[Value]| {
|
|
168
249
|
Value::Bool(tishlang_runtime::ws_send_native(
|
|
169
250
|
args.first().unwrap_or(&Value::Null),
|
|
170
251
|
&args
|
|
@@ -172,10 +253,10 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
|
|
|
172
253
|
.map(|v| v.to_display_string())
|
|
173
254
|
.unwrap_or_default(),
|
|
174
255
|
))
|
|
175
|
-
}))
|
|
176
|
-
"wsBroadcast" => Some(Value::
|
|
256
|
+
})),
|
|
257
|
+
"wsBroadcast" => Some(Value::native(|args: &[Value]| {
|
|
177
258
|
tishlang_runtime::ws_broadcast_native(args)
|
|
178
|
-
}))
|
|
259
|
+
})),
|
|
179
260
|
_ => None,
|
|
180
261
|
};
|
|
181
262
|
}
|
|
@@ -218,217 +299,223 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
218
299
|
let mut console = ObjectMap::default();
|
|
219
300
|
console.insert(
|
|
220
301
|
"debug".into(),
|
|
221
|
-
Value::
|
|
302
|
+
Value::native(|args: &[Value]| {
|
|
222
303
|
let s =
|
|
223
304
|
tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
|
|
224
305
|
vm_log(&s);
|
|
225
306
|
Value::Null
|
|
226
|
-
})
|
|
307
|
+
}),
|
|
227
308
|
);
|
|
228
309
|
console.insert(
|
|
229
310
|
"log".into(),
|
|
230
|
-
Value::
|
|
311
|
+
Value::native(|args: &[Value]| {
|
|
231
312
|
let s =
|
|
232
313
|
tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
|
|
233
314
|
vm_log(&s);
|
|
234
315
|
Value::Null
|
|
235
|
-
})
|
|
316
|
+
}),
|
|
236
317
|
);
|
|
237
318
|
console.insert(
|
|
238
319
|
"info".into(),
|
|
239
|
-
Value::
|
|
320
|
+
Value::native(|args: &[Value]| {
|
|
240
321
|
let s =
|
|
241
322
|
tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
|
|
242
323
|
vm_log(&s);
|
|
243
324
|
Value::Null
|
|
244
|
-
})
|
|
325
|
+
}),
|
|
245
326
|
);
|
|
246
327
|
console.insert(
|
|
247
328
|
"warn".into(),
|
|
248
|
-
Value::
|
|
329
|
+
Value::native(|args: &[Value]| {
|
|
249
330
|
let s =
|
|
250
331
|
tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
|
|
251
332
|
vm_log_err(&s);
|
|
252
333
|
Value::Null
|
|
253
|
-
})
|
|
334
|
+
}),
|
|
254
335
|
);
|
|
255
336
|
console.insert(
|
|
256
337
|
"error".into(),
|
|
257
|
-
Value::
|
|
338
|
+
Value::native(|args: &[Value]| {
|
|
258
339
|
let s =
|
|
259
340
|
tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
|
|
260
341
|
vm_log_err(&s);
|
|
261
342
|
Value::Null
|
|
262
|
-
})
|
|
343
|
+
}),
|
|
263
344
|
);
|
|
264
345
|
g.insert(
|
|
265
346
|
"console".into(),
|
|
266
|
-
Value::Object(
|
|
347
|
+
Value::Object(VmRef::new(console)),
|
|
267
348
|
);
|
|
268
349
|
|
|
269
350
|
let mut math = ObjectMap::default();
|
|
270
351
|
math.insert(
|
|
271
352
|
"abs".into(),
|
|
272
|
-
Value::
|
|
353
|
+
Value::native(|args: &[Value]| {
|
|
273
354
|
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
274
355
|
Value::Number(n.abs())
|
|
275
|
-
})
|
|
356
|
+
}),
|
|
276
357
|
);
|
|
277
358
|
math.insert(
|
|
278
359
|
"sqrt".into(),
|
|
279
|
-
Value::
|
|
360
|
+
Value::native(|args: &[Value]| {
|
|
280
361
|
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
281
362
|
Value::Number(n.sqrt())
|
|
282
|
-
})
|
|
363
|
+
}),
|
|
283
364
|
);
|
|
284
365
|
math.insert(
|
|
285
366
|
"floor".into(),
|
|
286
|
-
Value::
|
|
367
|
+
Value::native(|args: &[Value]| {
|
|
287
368
|
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
288
369
|
Value::Number(n.floor())
|
|
289
|
-
})
|
|
370
|
+
}),
|
|
290
371
|
);
|
|
291
372
|
math.insert(
|
|
292
373
|
"ceil".into(),
|
|
293
|
-
Value::
|
|
374
|
+
Value::native(|args: &[Value]| {
|
|
294
375
|
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
295
376
|
Value::Number(n.ceil())
|
|
296
|
-
})
|
|
377
|
+
}),
|
|
297
378
|
);
|
|
298
379
|
math.insert(
|
|
299
380
|
"round".into(),
|
|
300
|
-
Value::
|
|
381
|
+
Value::native(|args: &[Value]| {
|
|
301
382
|
let n = args.first().and_then(|v| v.as_number()).unwrap_or(f64::NAN);
|
|
302
383
|
Value::Number(n.round())
|
|
303
|
-
})
|
|
384
|
+
}),
|
|
304
385
|
);
|
|
305
386
|
math.insert(
|
|
306
387
|
"random".into(),
|
|
307
|
-
Value::
|
|
388
|
+
Value::native(|_| Value::Number(rand::random::<f64>())),
|
|
308
389
|
);
|
|
309
390
|
math.insert(
|
|
310
391
|
"min".into(),
|
|
311
|
-
Value::
|
|
392
|
+
Value::native(|args: &[Value]| {
|
|
312
393
|
let nums: Vec<f64> = args.iter().filter_map(|v| v.as_number()).collect();
|
|
313
394
|
Value::Number(nums.into_iter().fold(f64::NAN, |a, b| a.min(b)))
|
|
314
|
-
})
|
|
395
|
+
}),
|
|
315
396
|
);
|
|
316
397
|
math.insert(
|
|
317
398
|
"max".into(),
|
|
318
|
-
Value::
|
|
399
|
+
Value::native(|args: &[Value]| {
|
|
319
400
|
let nums: Vec<f64> = args.iter().filter_map(|v| v.as_number()).collect();
|
|
320
401
|
Value::Number(nums.into_iter().fold(f64::NAN, |a, b| a.max(b)))
|
|
321
|
-
})
|
|
402
|
+
}),
|
|
322
403
|
);
|
|
323
404
|
math.insert(
|
|
324
405
|
"pow".into(),
|
|
325
|
-
Value::
|
|
406
|
+
Value::native(|args: &[Value]| math_builtins::pow(args)),
|
|
326
407
|
);
|
|
327
408
|
math.insert(
|
|
328
409
|
"sin".into(),
|
|
329
|
-
Value::
|
|
410
|
+
Value::native(|args: &[Value]| math_builtins::sin(args)),
|
|
330
411
|
);
|
|
331
412
|
math.insert(
|
|
332
413
|
"cos".into(),
|
|
333
|
-
Value::
|
|
414
|
+
Value::native(|args: &[Value]| math_builtins::cos(args)),
|
|
334
415
|
);
|
|
335
416
|
math.insert(
|
|
336
417
|
"tan".into(),
|
|
337
|
-
Value::
|
|
418
|
+
Value::native(|args: &[Value]| math_builtins::tan(args)),
|
|
338
419
|
);
|
|
339
420
|
math.insert(
|
|
340
421
|
"log".into(),
|
|
341
|
-
Value::
|
|
422
|
+
Value::native(|args: &[Value]| math_builtins::log(args)),
|
|
342
423
|
);
|
|
343
424
|
math.insert(
|
|
344
425
|
"exp".into(),
|
|
345
|
-
Value::
|
|
426
|
+
Value::native(|args: &[Value]| math_builtins::exp(args)),
|
|
346
427
|
);
|
|
347
428
|
math.insert(
|
|
348
429
|
"sign".into(),
|
|
349
|
-
Value::
|
|
430
|
+
Value::native(|args: &[Value]| math_builtins::sign(args)),
|
|
350
431
|
);
|
|
351
432
|
math.insert(
|
|
352
433
|
"trunc".into(),
|
|
353
|
-
Value::
|
|
434
|
+
Value::native(|args: &[Value]| math_builtins::trunc(args)),
|
|
354
435
|
);
|
|
355
436
|
math.insert("PI".into(), Value::Number(std::f64::consts::PI));
|
|
356
437
|
math.insert("E".into(), Value::Number(std::f64::consts::E));
|
|
357
|
-
g.insert("Math".into(), Value::Object(
|
|
438
|
+
g.insert("Math".into(), Value::Object(VmRef::new(math)));
|
|
358
439
|
|
|
359
440
|
let mut json = ObjectMap::default();
|
|
360
441
|
json.insert(
|
|
361
442
|
"parse".into(),
|
|
362
|
-
Value::
|
|
443
|
+
Value::native(|args: &[Value]| {
|
|
363
444
|
let s = args
|
|
364
445
|
.first()
|
|
365
446
|
.map(|v| v.to_display_string())
|
|
366
447
|
.unwrap_or_default();
|
|
367
448
|
tishlang_core::json_parse(&s).unwrap_or(Value::Null)
|
|
368
|
-
})
|
|
449
|
+
}),
|
|
369
450
|
);
|
|
370
451
|
json.insert(
|
|
371
452
|
"stringify".into(),
|
|
372
|
-
Value::
|
|
453
|
+
Value::native(|args: &[Value]| {
|
|
373
454
|
let v = args.first().unwrap_or(&Value::Null);
|
|
374
455
|
Value::String(tishlang_core::json_stringify(v).into())
|
|
375
|
-
})
|
|
456
|
+
}),
|
|
376
457
|
);
|
|
377
|
-
g.insert("JSON".into(), Value::Object(
|
|
458
|
+
g.insert("JSON".into(), Value::Object(VmRef::new(json)));
|
|
378
459
|
|
|
379
460
|
g.insert(
|
|
380
461
|
"parseInt".into(),
|
|
381
|
-
Value::
|
|
462
|
+
Value::native(|args: &[Value]| globals_builtins::parse_int(args)),
|
|
382
463
|
);
|
|
383
464
|
g.insert(
|
|
384
465
|
"parseFloat".into(),
|
|
385
|
-
Value::
|
|
466
|
+
Value::native(|args: &[Value]| {
|
|
386
467
|
globals_builtins::parse_float(args)
|
|
387
|
-
})
|
|
468
|
+
}),
|
|
388
469
|
);
|
|
389
470
|
g.insert(
|
|
390
471
|
"encodeURI".into(),
|
|
391
|
-
Value::
|
|
472
|
+
Value::native(|args: &[Value]| globals_builtins::encode_uri(args)),
|
|
392
473
|
);
|
|
393
474
|
g.insert(
|
|
394
475
|
"decodeURI".into(),
|
|
395
|
-
Value::
|
|
476
|
+
Value::native(|args: &[Value]| globals_builtins::decode_uri(args)),
|
|
477
|
+
);
|
|
478
|
+
g.insert(
|
|
479
|
+
"htmlEscape".into(),
|
|
480
|
+
Value::native(|args: &[Value]| {
|
|
481
|
+
tishlang_builtins::string::escape_html(args.first().unwrap_or(&Value::Null))
|
|
482
|
+
}),
|
|
396
483
|
);
|
|
397
484
|
g.insert(
|
|
398
485
|
"Boolean".into(),
|
|
399
|
-
Value::
|
|
486
|
+
Value::native(|args: &[Value]| globals_builtins::boolean(args)),
|
|
400
487
|
);
|
|
401
488
|
g.insert(
|
|
402
489
|
"isFinite".into(),
|
|
403
|
-
Value::
|
|
490
|
+
Value::native(|args: &[Value]| globals_builtins::is_finite(args)),
|
|
404
491
|
);
|
|
405
492
|
g.insert(
|
|
406
493
|
"isNaN".into(),
|
|
407
|
-
Value::
|
|
494
|
+
Value::native(|args: &[Value]| globals_builtins::is_nan(args)),
|
|
408
495
|
);
|
|
409
496
|
g.insert("Infinity".into(), Value::Number(f64::INFINITY));
|
|
410
497
|
g.insert("NaN".into(), Value::Number(f64::NAN));
|
|
411
498
|
g.insert(
|
|
412
499
|
"typeof".into(),
|
|
413
|
-
Value::
|
|
500
|
+
Value::native(|args: &[Value]| {
|
|
414
501
|
let v = args.first().unwrap_or(&Value::Null);
|
|
415
502
|
Value::String(v.type_name().into())
|
|
416
|
-
})
|
|
503
|
+
}),
|
|
417
504
|
);
|
|
418
505
|
|
|
419
506
|
// Date - at minimum Date.now() for timing
|
|
420
507
|
let mut date = ObjectMap::default();
|
|
421
508
|
date.insert(
|
|
422
509
|
"now".into(),
|
|
423
|
-
Value::
|
|
510
|
+
Value::native(|_args: &[Value]| {
|
|
424
511
|
let ms = std::time::SystemTime::now()
|
|
425
512
|
.duration_since(std::time::UNIX_EPOCH)
|
|
426
513
|
.unwrap_or_default()
|
|
427
514
|
.as_millis() as f64;
|
|
428
515
|
Value::Number(ms)
|
|
429
|
-
})
|
|
516
|
+
}),
|
|
430
517
|
);
|
|
431
|
-
g.insert("Date".into(), Value::Object(
|
|
518
|
+
g.insert("Date".into(), Value::Object(VmRef::new(date)));
|
|
432
519
|
|
|
433
520
|
g.insert(
|
|
434
521
|
"Uint8Array".into(),
|
|
@@ -443,102 +530,102 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
443
530
|
let mut object_methods = ObjectMap::default();
|
|
444
531
|
object_methods.insert(
|
|
445
532
|
"assign".into(),
|
|
446
|
-
Value::
|
|
533
|
+
Value::native(|args: &[Value]| {
|
|
447
534
|
globals_builtins::object_assign(args)
|
|
448
|
-
})
|
|
535
|
+
}),
|
|
449
536
|
);
|
|
450
537
|
object_methods.insert(
|
|
451
538
|
"fromEntries".into(),
|
|
452
|
-
Value::
|
|
539
|
+
Value::native(|args: &[Value]| {
|
|
453
540
|
globals_builtins::object_from_entries(args)
|
|
454
|
-
})
|
|
541
|
+
}),
|
|
455
542
|
);
|
|
456
543
|
object_methods.insert(
|
|
457
544
|
"keys".into(),
|
|
458
|
-
Value::
|
|
545
|
+
Value::native(|args: &[Value]| {
|
|
459
546
|
globals_builtins::object_keys(args)
|
|
460
|
-
})
|
|
547
|
+
}),
|
|
461
548
|
);
|
|
462
549
|
object_methods.insert(
|
|
463
550
|
"values".into(),
|
|
464
|
-
Value::
|
|
551
|
+
Value::native(|args: &[Value]| {
|
|
465
552
|
globals_builtins::object_values(args)
|
|
466
|
-
})
|
|
553
|
+
}),
|
|
467
554
|
);
|
|
468
555
|
object_methods.insert(
|
|
469
556
|
"entries".into(),
|
|
470
|
-
Value::
|
|
557
|
+
Value::native(|args: &[Value]| {
|
|
471
558
|
globals_builtins::object_entries(args)
|
|
472
|
-
})
|
|
559
|
+
}),
|
|
473
560
|
);
|
|
474
561
|
g.insert(
|
|
475
562
|
"Object".into(),
|
|
476
|
-
Value::Object(
|
|
563
|
+
Value::Object(VmRef::new(object_methods)),
|
|
477
564
|
);
|
|
478
565
|
|
|
479
566
|
// Array.isArray
|
|
480
567
|
let mut array_static = ObjectMap::default();
|
|
481
568
|
array_static.insert(
|
|
482
569
|
"isArray".into(),
|
|
483
|
-
Value::
|
|
570
|
+
Value::native(|args: &[Value]| {
|
|
484
571
|
globals_builtins::array_is_array(args)
|
|
485
|
-
})
|
|
572
|
+
}),
|
|
486
573
|
);
|
|
487
574
|
g.insert(
|
|
488
575
|
"Array".into(),
|
|
489
|
-
Value::Object(
|
|
576
|
+
Value::Object(VmRef::new(array_static)),
|
|
490
577
|
);
|
|
491
578
|
|
|
492
579
|
// String(value) as callable + String.fromCharCode
|
|
493
|
-
let string_convert_fn = Value::
|
|
580
|
+
let string_convert_fn = Value::native(|args: &[Value]| {
|
|
494
581
|
globals_builtins::string_convert(args)
|
|
495
|
-
})
|
|
582
|
+
});
|
|
496
583
|
let mut string_static = ObjectMap::default();
|
|
497
584
|
string_static.insert(
|
|
498
585
|
"fromCharCode".into(),
|
|
499
|
-
Value::
|
|
586
|
+
Value::native(|args: &[Value]| {
|
|
500
587
|
globals_builtins::string_from_char_code(args)
|
|
501
|
-
})
|
|
588
|
+
}),
|
|
502
589
|
);
|
|
503
590
|
string_static.insert(Arc::from("__call"), string_convert_fn);
|
|
504
591
|
g.insert(
|
|
505
592
|
"String".into(),
|
|
506
|
-
Value::Object(
|
|
593
|
+
Value::Object(VmRef::new(string_static)),
|
|
507
594
|
);
|
|
508
595
|
|
|
509
596
|
// JSX / Lattish: stubs for bytecode VM when no DOM (e.g. console). Override via set_global in browser.
|
|
510
597
|
g.insert(
|
|
511
598
|
"h".into(),
|
|
512
|
-
Value::
|
|
599
|
+
Value::native(|_args: &[Value]| Value::Null),
|
|
513
600
|
);
|
|
514
601
|
g.insert(
|
|
515
602
|
"Fragment".into(),
|
|
516
|
-
Value::Object(
|
|
603
|
+
Value::Object(VmRef::new(ObjectMap::default())),
|
|
517
604
|
);
|
|
518
605
|
g.insert(
|
|
519
606
|
"createRoot".into(),
|
|
520
|
-
Value::
|
|
607
|
+
Value::native(|_args: &[Value]| {
|
|
521
608
|
let mut render_obj = ObjectMap::default();
|
|
522
609
|
render_obj.insert(
|
|
523
610
|
"render".into(),
|
|
524
|
-
Value::
|
|
611
|
+
Value::native(|_args: &[Value]| Value::Null),
|
|
525
612
|
);
|
|
526
|
-
Value::Object(
|
|
527
|
-
})
|
|
613
|
+
Value::Object(VmRef::new(render_obj))
|
|
614
|
+
}),
|
|
528
615
|
);
|
|
529
616
|
g.insert(
|
|
530
617
|
"useState".into(),
|
|
531
|
-
Value::
|
|
618
|
+
Value::native(|args: &[Value]| {
|
|
532
619
|
let init = args.first().cloned().unwrap_or(Value::Null);
|
|
533
|
-
let arr = vec![init, Value::
|
|
534
|
-
Value::Array(
|
|
535
|
-
})
|
|
620
|
+
let arr = vec![init, Value::native(|_| Value::Null)];
|
|
621
|
+
Value::Array(VmRef::new(arr))
|
|
622
|
+
}),
|
|
536
623
|
);
|
|
537
624
|
let mut document_obj = ObjectMap::default();
|
|
538
625
|
document_obj.insert("body".into(), Value::Null);
|
|
539
626
|
g.insert(
|
|
540
627
|
"document".into(),
|
|
541
|
-
Value::Object(
|
|
628
|
+
Value::Object(VmRef::new(document_obj)),
|
|
542
629
|
);
|
|
543
630
|
|
|
544
631
|
#[cfg(feature = "process")]
|
|
@@ -546,54 +633,122 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
546
633
|
let mut process_obj = ObjectMap::default();
|
|
547
634
|
process_obj.insert(
|
|
548
635
|
"exit".into(),
|
|
549
|
-
Value::
|
|
636
|
+
Value::native(|args: &[Value]| {
|
|
550
637
|
tishlang_runtime::process_exit(args)
|
|
551
|
-
})
|
|
638
|
+
}),
|
|
552
639
|
);
|
|
553
640
|
process_obj.insert(
|
|
554
641
|
"cwd".into(),
|
|
555
|
-
Value::
|
|
642
|
+
Value::native(|args: &[Value]| {
|
|
556
643
|
tishlang_runtime::process_cwd(args)
|
|
557
|
-
})
|
|
644
|
+
}),
|
|
558
645
|
);
|
|
559
646
|
process_obj.insert(
|
|
560
647
|
"exec".into(),
|
|
561
|
-
Value::
|
|
648
|
+
Value::native(|args: &[Value]| {
|
|
562
649
|
tishlang_runtime::process_exec(args)
|
|
563
|
-
})
|
|
650
|
+
}),
|
|
564
651
|
);
|
|
565
652
|
process_obj.insert(
|
|
566
653
|
"argv".into(),
|
|
567
|
-
Value::Array(
|
|
654
|
+
Value::Array(VmRef::new(
|
|
568
655
|
std::env::args().map(|s| Value::String(s.into())).collect(),
|
|
569
|
-
))
|
|
656
|
+
)),
|
|
570
657
|
);
|
|
571
658
|
process_obj.insert(
|
|
572
659
|
"env".into(),
|
|
573
|
-
Value::Object(
|
|
660
|
+
Value::Object(VmRef::new(
|
|
574
661
|
std::env::vars()
|
|
575
662
|
.map(|(k, v)| (Arc::from(k.as_str()), Value::String(v.into())))
|
|
576
663
|
.collect(),
|
|
577
|
-
))
|
|
664
|
+
)),
|
|
578
665
|
);
|
|
579
666
|
g.insert(
|
|
580
667
|
"process".into(),
|
|
581
|
-
Value::Object(
|
|
668
|
+
Value::Object(VmRef::new(process_obj)),
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
#[cfg(feature = "timers")]
|
|
673
|
+
if cap_allows(enabled, "timers") {
|
|
674
|
+
g.insert(
|
|
675
|
+
"setTimeout".into(),
|
|
676
|
+
Value::native(|args: &[Value]| tishlang_runtime::timer_set_timeout(args)),
|
|
677
|
+
);
|
|
678
|
+
g.insert(
|
|
679
|
+
"clearTimeout".into(),
|
|
680
|
+
Value::native(|args: &[Value]| tishlang_runtime::timer_clear_timeout(args)),
|
|
681
|
+
);
|
|
682
|
+
g.insert(
|
|
683
|
+
"setInterval".into(),
|
|
684
|
+
Value::native(|args: &[Value]| tishlang_runtime::timer_set_interval(args)),
|
|
685
|
+
);
|
|
686
|
+
g.insert(
|
|
687
|
+
"clearInterval".into(),
|
|
688
|
+
Value::native(|args: &[Value]| tishlang_runtime::timer_clear_interval(args)),
|
|
582
689
|
);
|
|
583
690
|
}
|
|
584
691
|
|
|
585
692
|
#[cfg(feature = "http")]
|
|
586
693
|
if cap_allows(enabled, "http") {
|
|
694
|
+
g.insert(
|
|
695
|
+
"fetch".into(),
|
|
696
|
+
Value::native(|args: &[Value]| tishlang_runtime::fetch_promise(args.to_vec())),
|
|
697
|
+
);
|
|
698
|
+
g.insert(
|
|
699
|
+
"fetchAll".into(),
|
|
700
|
+
Value::native(|args: &[Value]| tishlang_runtime::fetch_all_promise(args.to_vec())),
|
|
701
|
+
);
|
|
702
|
+
g.insert("Promise".into(), tishlang_runtime::promise_object());
|
|
703
|
+
g.insert(
|
|
704
|
+
"registerStaticRoute".into(),
|
|
705
|
+
Value::native(|args: &[Value]| {
|
|
706
|
+
let path = match args.first() {
|
|
707
|
+
Some(Value::String(s)) => s.to_string(),
|
|
708
|
+
_ => return Value::Null,
|
|
709
|
+
};
|
|
710
|
+
let body = match args.get(1) {
|
|
711
|
+
Some(Value::String(s)) => s.as_bytes().to_vec(),
|
|
712
|
+
_ => return Value::Null,
|
|
713
|
+
};
|
|
714
|
+
let ct = match args.get(2) {
|
|
715
|
+
Some(Value::String(s)) => s.to_string(),
|
|
716
|
+
_ => "application/octet-stream".to_string(),
|
|
717
|
+
};
|
|
718
|
+
tishlang_runtime::register_static_route(&path, &body, &ct);
|
|
719
|
+
Value::Null
|
|
720
|
+
}),
|
|
721
|
+
);
|
|
587
722
|
g.insert(
|
|
588
723
|
"serve".into(),
|
|
589
|
-
Value::
|
|
590
|
-
|
|
591
|
-
|
|
724
|
+
Value::native(|args: &[Value]| {
|
|
725
|
+
// Phase-1 item 2 (see tish:http.serve above for full docs).
|
|
726
|
+
let raw = args.get(1).cloned().unwrap_or(Value::Null);
|
|
727
|
+
let handler_value = match raw {
|
|
728
|
+
Value::Function(_) => raw,
|
|
729
|
+
Value::Object(ref obj) => {
|
|
730
|
+
let obj_ref = obj.borrow();
|
|
731
|
+
if let Some(Value::Function(on_worker)) =
|
|
732
|
+
obj_ref.get(&std::sync::Arc::from("onWorker")).cloned()
|
|
733
|
+
{
|
|
734
|
+
let args_for_init = [Value::Number(0.0)];
|
|
735
|
+
on_worker(&args_for_init)
|
|
736
|
+
} else if let Some(h) =
|
|
737
|
+
obj_ref.get(&std::sync::Arc::from("handler")).cloned()
|
|
738
|
+
{
|
|
739
|
+
h
|
|
740
|
+
} else {
|
|
741
|
+
Value::Null
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
_ => Value::Null,
|
|
745
|
+
};
|
|
746
|
+
if let Value::Function(f) = handler_value {
|
|
592
747
|
tishlang_runtime::http_serve(args, move |req_args| f(req_args))
|
|
593
748
|
} else {
|
|
594
749
|
Value::Null
|
|
595
750
|
}
|
|
596
|
-
})
|
|
751
|
+
}),
|
|
597
752
|
);
|
|
598
753
|
}
|
|
599
754
|
|
|
@@ -601,7 +756,7 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
|
|
|
601
756
|
}
|
|
602
757
|
|
|
603
758
|
/// Shared scope for closure capture (parent frame's locals).
|
|
604
|
-
type ScopeMap =
|
|
759
|
+
type ScopeMap = VmRef<ObjectMap>;
|
|
605
760
|
|
|
606
761
|
/// Options for the convenience [`run_with_options`] helper (one-shot VM run from the CLI).
|
|
607
762
|
#[derive(Clone, Debug, Default)]
|
|
@@ -618,9 +773,14 @@ pub struct Vm {
|
|
|
618
773
|
scope: ObjectMap,
|
|
619
774
|
/// Enclosing scope for closures (captured parent frame locals).
|
|
620
775
|
enclosing: Option<ScopeMap>,
|
|
621
|
-
globals:
|
|
776
|
+
globals: VmRef<ObjectMap>,
|
|
622
777
|
/// Capabilities for `LoadNativeExport` and globals such as `process` / `serve`.
|
|
623
778
|
capabilities: Arc<HashSet<String>>,
|
|
779
|
+
/// Externally registered native modules, keyed by import spec (e.g.
|
|
780
|
+
/// `"cargo:tish_pg"`). Populated by embedders before `run` (see
|
|
781
|
+
/// [`register_native_module`]). Phase-2 item 11: unblocks `cargo:`
|
|
782
|
+
/// imports on the cranelift and llvm backends which run this VM.
|
|
783
|
+
native_modules: VmRef<HashMap<String, VmRef<ObjectMap>>>,
|
|
624
784
|
}
|
|
625
785
|
|
|
626
786
|
impl Vm {
|
|
@@ -639,11 +799,24 @@ impl Vm {
|
|
|
639
799
|
stack: Vec::new(),
|
|
640
800
|
scope: ObjectMap::default(),
|
|
641
801
|
enclosing: None,
|
|
642
|
-
globals:
|
|
802
|
+
globals: VmRef::new(init_globals(capabilities.as_ref())),
|
|
643
803
|
capabilities,
|
|
804
|
+
native_modules: VmRef::new(HashMap::new()),
|
|
644
805
|
}
|
|
645
806
|
}
|
|
646
807
|
|
|
808
|
+
/// Register an externally-supplied native module under a `cargo:`-style
|
|
809
|
+
/// spec (e.g. `"cargo:tish_pg"`). The `exports` map is what
|
|
810
|
+
/// `LoadNativeExport` will index into when user code imports from this
|
|
811
|
+
/// spec. Intended to be called by the `tishlang_cranelift_runtime` /
|
|
812
|
+
/// `tishlang_llvm` link step, or by external embedders that want to
|
|
813
|
+
/// expose Rust crates to `.tish` programs running on the bytecode VM.
|
|
814
|
+
pub fn register_native_module(&mut self, spec: impl Into<String>, exports: ObjectMap) {
|
|
815
|
+
self.native_modules
|
|
816
|
+
.borrow_mut()
|
|
817
|
+
.insert(spec.into(), VmRef::new(exports));
|
|
818
|
+
}
|
|
819
|
+
|
|
647
820
|
pub fn get_global(&self, name: &str) -> Option<Value> {
|
|
648
821
|
self.globals.borrow().get(name).cloned()
|
|
649
822
|
}
|
|
@@ -672,6 +845,22 @@ impl Vm {
|
|
|
672
845
|
Self::read_u16(code, ip) as i16
|
|
673
846
|
}
|
|
674
847
|
|
|
848
|
+
/// Pop innermost try handler, truncate stack, push thrown value, jump to catch.
|
|
849
|
+
fn unwind_throw(
|
|
850
|
+
try_handlers: &mut Vec<(usize, usize)>,
|
|
851
|
+
stack: &mut Vec<Value>,
|
|
852
|
+
ip: &mut usize,
|
|
853
|
+
v: Value,
|
|
854
|
+
) -> Result<(), String> {
|
|
855
|
+
let (catch_ip, stack_len) = try_handlers
|
|
856
|
+
.pop()
|
|
857
|
+
.ok_or_else(|| format!("Uncaught throw: {}", v.to_display_string()))?;
|
|
858
|
+
stack.truncate(stack_len);
|
|
859
|
+
stack.push(v);
|
|
860
|
+
*ip = catch_ip;
|
|
861
|
+
Ok(())
|
|
862
|
+
}
|
|
863
|
+
|
|
675
864
|
pub fn run(&mut self, chunk: &Chunk) -> Result<Value, String> {
|
|
676
865
|
self.run_with_options(chunk, false)
|
|
677
866
|
}
|
|
@@ -693,7 +882,7 @@ impl Vm {
|
|
|
693
882
|
let names = &chunk.names;
|
|
694
883
|
|
|
695
884
|
let mut ip = 0;
|
|
696
|
-
let local_scope: ScopeMap =
|
|
885
|
+
let local_scope: ScopeMap = VmRef::new(ObjectMap::default());
|
|
697
886
|
{
|
|
698
887
|
let mut ls = local_scope.borrow_mut();
|
|
699
888
|
let param_count = chunk.param_count as usize;
|
|
@@ -707,7 +896,7 @@ impl Vm {
|
|
|
707
896
|
let rest_arr: Vec<Value> = args.iter().skip(ri).cloned().collect();
|
|
708
897
|
ls.insert(
|
|
709
898
|
Arc::clone(name),
|
|
710
|
-
Value::Array(
|
|
899
|
+
Value::Array(VmRef::new(rest_arr)),
|
|
711
900
|
);
|
|
712
901
|
}
|
|
713
902
|
}
|
|
@@ -750,20 +939,22 @@ impl Vm {
|
|
|
750
939
|
.get(*nested_idx)
|
|
751
940
|
.ok_or_else(|| "Nested chunk index out of bounds".to_string())?;
|
|
752
941
|
let inner_clone = inner.clone();
|
|
753
|
-
let globals =
|
|
754
|
-
let enclosing = Some(
|
|
942
|
+
let globals = self.globals.clone();
|
|
943
|
+
let enclosing = Some(local_scope.clone());
|
|
755
944
|
let capabilities = Arc::clone(&self.capabilities);
|
|
756
|
-
|
|
945
|
+
let native_modules = self.native_modules.clone();
|
|
946
|
+
Value::native(move |args: &[Value]| {
|
|
757
947
|
let mut vm = Vm {
|
|
758
948
|
stack: Vec::new(),
|
|
759
949
|
scope: ObjectMap::default(),
|
|
760
950
|
enclosing: enclosing.clone(),
|
|
761
|
-
globals:
|
|
951
|
+
globals: globals.clone(),
|
|
762
952
|
capabilities: Arc::clone(&capabilities),
|
|
953
|
+
native_modules: native_modules.clone(),
|
|
763
954
|
};
|
|
764
955
|
vm.run_chunk(&inner_clone, &inner_clone.nested, args, false)
|
|
765
956
|
.unwrap_or(Value::Null)
|
|
766
|
-
})
|
|
957
|
+
})
|
|
767
958
|
}
|
|
768
959
|
};
|
|
769
960
|
self.stack.push(v);
|
|
@@ -937,12 +1128,12 @@ impl Vm {
|
|
|
937
1128
|
.pop()
|
|
938
1129
|
.ok_or_else(|| "Stack underflow: no callee".to_string())?;
|
|
939
1130
|
let f = match &callee {
|
|
940
|
-
Value::Function(f) =>
|
|
1131
|
+
Value::Function(f) => f.clone(),
|
|
941
1132
|
Value::Object(o) => {
|
|
942
1133
|
if let Some(Value::Function(call_fn)) =
|
|
943
1134
|
o.borrow().get(&Arc::from("__call"))
|
|
944
1135
|
{
|
|
945
|
-
|
|
1136
|
+
call_fn.clone()
|
|
946
1137
|
} else {
|
|
947
1138
|
return Err(format!(
|
|
948
1139
|
"Call of non-function: {}",
|
|
@@ -976,12 +1167,12 @@ impl Vm {
|
|
|
976
1167
|
}
|
|
977
1168
|
};
|
|
978
1169
|
let f = match &callee {
|
|
979
|
-
Value::Function(f) =>
|
|
1170
|
+
Value::Function(f) => f.clone(),
|
|
980
1171
|
Value::Object(o) => {
|
|
981
1172
|
if let Some(Value::Function(call_fn)) =
|
|
982
1173
|
o.borrow().get(&Arc::from("__call"))
|
|
983
1174
|
{
|
|
984
|
-
|
|
1175
|
+
call_fn.clone()
|
|
985
1176
|
} else {
|
|
986
1177
|
return Err(format!(
|
|
987
1178
|
"Call of non-function: {}",
|
|
@@ -1168,7 +1359,7 @@ impl Vm {
|
|
|
1168
1359
|
);
|
|
1169
1360
|
}
|
|
1170
1361
|
elems.reverse();
|
|
1171
|
-
self.stack.push(Value::Array(
|
|
1362
|
+
self.stack.push(Value::Array(VmRef::new(elems)));
|
|
1172
1363
|
}
|
|
1173
1364
|
Opcode::NewObject => {
|
|
1174
1365
|
let n = Self::read_u16(code, &mut ip) as usize;
|
|
@@ -1185,7 +1376,7 @@ impl Vm {
|
|
|
1185
1376
|
let key = key_val.to_display_string().into();
|
|
1186
1377
|
map.insert(key, val);
|
|
1187
1378
|
}
|
|
1188
|
-
self.stack.push(Value::Object(
|
|
1379
|
+
self.stack.push(Value::Object(VmRef::new(map)));
|
|
1189
1380
|
}
|
|
1190
1381
|
Opcode::EnterTry => {
|
|
1191
1382
|
let offset = Self::read_u16(code, &mut ip) as usize;
|
|
@@ -1225,7 +1416,7 @@ impl Vm {
|
|
|
1225
1416
|
},
|
|
1226
1417
|
);
|
|
1227
1418
|
a.extend(b);
|
|
1228
|
-
self.stack.push(Value::Array(
|
|
1419
|
+
self.stack.push(Value::Array(VmRef::new(a)));
|
|
1229
1420
|
}
|
|
1230
1421
|
Opcode::MergeObject => {
|
|
1231
1422
|
let right = self
|
|
@@ -1260,7 +1451,7 @@ impl Vm {
|
|
|
1260
1451
|
));
|
|
1261
1452
|
}
|
|
1262
1453
|
self.stack
|
|
1263
|
-
.push(Value::Object(
|
|
1454
|
+
.push(Value::Object(VmRef::new(merged)));
|
|
1264
1455
|
}
|
|
1265
1456
|
Opcode::ArraySortNumeric => {
|
|
1266
1457
|
let operand = Self::read_u16(code, &mut ip);
|
|
@@ -1302,7 +1493,7 @@ impl Vm {
|
|
|
1302
1493
|
.pop()
|
|
1303
1494
|
.ok_or_else(|| "Stack underflow".to_string())?;
|
|
1304
1495
|
let result = match &arr {
|
|
1305
|
-
Value::Array(a) => Value::Array(
|
|
1496
|
+
Value::Array(a) => Value::Array(VmRef::new(a.borrow().clone())),
|
|
1306
1497
|
_ => Value::Null,
|
|
1307
1498
|
};
|
|
1308
1499
|
self.stack.push(result);
|
|
@@ -1341,7 +1532,7 @@ impl Vm {
|
|
|
1341
1532
|
eval_binop(binop, &l, &r).unwrap_or(Value::Null)
|
|
1342
1533
|
})
|
|
1343
1534
|
.collect();
|
|
1344
|
-
Value::Array(
|
|
1535
|
+
Value::Array(VmRef::new(mapped))
|
|
1345
1536
|
} else {
|
|
1346
1537
|
Value::Null
|
|
1347
1538
|
};
|
|
@@ -1384,7 +1575,7 @@ impl Vm {
|
|
|
1384
1575
|
})
|
|
1385
1576
|
.cloned()
|
|
1386
1577
|
.collect();
|
|
1387
|
-
Value::Array(
|
|
1578
|
+
Value::Array(VmRef::new(filtered))
|
|
1388
1579
|
} else {
|
|
1389
1580
|
Value::Null
|
|
1390
1581
|
};
|
|
@@ -1395,12 +1586,30 @@ impl Vm {
|
|
|
1395
1586
|
.stack
|
|
1396
1587
|
.pop()
|
|
1397
1588
|
.ok_or_else(|| "Stack underflow".to_string())?;
|
|
1398
|
-
|
|
1589
|
+
Self::unwind_throw(&mut try_handlers, &mut self.stack, &mut ip, v)?;
|
|
1590
|
+
}
|
|
1591
|
+
Opcode::AwaitPromise => {
|
|
1592
|
+
let v = self
|
|
1593
|
+
.stack
|
|
1399
1594
|
.pop()
|
|
1400
|
-
.ok_or_else(||
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1595
|
+
.ok_or_else(|| "Stack underflow in AwaitPromise".to_string())?;
|
|
1596
|
+
#[cfg(feature = "http")]
|
|
1597
|
+
{
|
|
1598
|
+
use tishlang_core::Value as V;
|
|
1599
|
+
match v {
|
|
1600
|
+
V::Promise(p) => match p.block_until_settled() {
|
|
1601
|
+
Ok(val) => self.stack.push(val),
|
|
1602
|
+
Err(rej) => {
|
|
1603
|
+
Self::unwind_throw(&mut try_handlers, &mut self.stack, &mut ip, rej)?;
|
|
1604
|
+
}
|
|
1605
|
+
},
|
|
1606
|
+
other => self.stack.push(tishlang_runtime::await_promise(other)),
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
#[cfg(not(feature = "http"))]
|
|
1610
|
+
{
|
|
1611
|
+
self.stack.push(v);
|
|
1612
|
+
}
|
|
1404
1613
|
}
|
|
1405
1614
|
Opcode::LoadNativeExport => {
|
|
1406
1615
|
let spec_idx = Self::read_u16(code, &mut ip);
|
|
@@ -1420,19 +1629,36 @@ impl Vm {
|
|
|
1420
1629
|
return Err("LoadNativeExport: export_name constant out of bounds or not string".to_string());
|
|
1421
1630
|
}
|
|
1422
1631
|
};
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
}
|
|
1632
|
+
// Phase-2 item 11: consult externally registered native
|
|
1633
|
+
// modules (populated via `Vm::register_native_module`)
|
|
1634
|
+
// before falling through to the built-in lookup. Embedders
|
|
1635
|
+
// on the cranelift / llvm backends that want to expose
|
|
1636
|
+
// `cargo:…` Rust crates should register the module's
|
|
1637
|
+
// exports map before calling `vm.run(chunk)`.
|
|
1638
|
+
let from_registry: Option<Value> = if spec.starts_with("cargo:") {
|
|
1639
|
+
let regs = self.native_modules.borrow();
|
|
1640
|
+
regs.get(spec)
|
|
1641
|
+
.and_then(|m| m.borrow().get(&Arc::from(export_name)).cloned())
|
|
1642
|
+
} else {
|
|
1643
|
+
None
|
|
1644
|
+
};
|
|
1645
|
+
let v = from_registry
|
|
1646
|
+
.or_else(|| get_builtin_export(self.capabilities.as_ref(), spec, export_name))
|
|
1647
|
+
.ok_or_else(|| {
|
|
1648
|
+
if spec.starts_with("cargo:") {
|
|
1649
|
+
format!(
|
|
1650
|
+
"cargo:{} is not registered on the bytecode VM. Embedders must call Vm::register_native_module before run(). Spec: {} export: {}",
|
|
1651
|
+
spec.trim_start_matches("cargo:"),
|
|
1652
|
+
spec,
|
|
1653
|
+
export_name,
|
|
1654
|
+
)
|
|
1655
|
+
} else {
|
|
1656
|
+
format!(
|
|
1657
|
+
"Built-in module '{}' does not export '{}' or capability not enabled for this run. Use e.g. tish run --feature fs (or full). The tish binary must also be built with that capability linked in.",
|
|
1658
|
+
spec, export_name
|
|
1659
|
+
)
|
|
1660
|
+
}
|
|
1661
|
+
})?;
|
|
1436
1662
|
self.stack.push(v);
|
|
1437
1663
|
}
|
|
1438
1664
|
Opcode::Closure | Opcode::LoadThis => {
|
|
@@ -1441,6 +1667,11 @@ impl Vm {
|
|
|
1441
1667
|
}
|
|
1442
1668
|
}
|
|
1443
1669
|
|
|
1670
|
+
#[cfg(feature = "timers")]
|
|
1671
|
+
if cap_allows(self.capabilities.as_ref(), "timers") {
|
|
1672
|
+
tishlang_runtime::drain_timers();
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1444
1675
|
Ok(self.stack.pop().unwrap_or(Value::Null))
|
|
1445
1676
|
}
|
|
1446
1677
|
}
|
|
@@ -1577,105 +1808,105 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
1577
1808
|
if key_s == "length" {
|
|
1578
1809
|
return Ok(Value::Number(a.borrow().len() as f64));
|
|
1579
1810
|
}
|
|
1580
|
-
let a_clone =
|
|
1811
|
+
let a_clone = a.clone();
|
|
1581
1812
|
let method: ArrayMethodFn = match key_s {
|
|
1582
|
-
"push" =>
|
|
1583
|
-
arr_builtins::push(&Value::Array(
|
|
1813
|
+
"push" => make_native_fn(move |args: &[Value]| {
|
|
1814
|
+
arr_builtins::push(&Value::Array(a_clone.clone()), args)
|
|
1584
1815
|
}),
|
|
1585
|
-
"pop" =>
|
|
1586
|
-
arr_builtins::pop(&Value::Array(
|
|
1816
|
+
"pop" => make_native_fn(move |_args: &[Value]| {
|
|
1817
|
+
arr_builtins::pop(&Value::Array(a_clone.clone()))
|
|
1587
1818
|
}),
|
|
1588
|
-
"shift" =>
|
|
1589
|
-
arr_builtins::shift(&Value::Array(
|
|
1819
|
+
"shift" => make_native_fn(move |_args: &[Value]| {
|
|
1820
|
+
arr_builtins::shift(&Value::Array(a_clone.clone()))
|
|
1590
1821
|
}),
|
|
1591
|
-
"unshift" =>
|
|
1592
|
-
arr_builtins::unshift(&Value::Array(
|
|
1822
|
+
"unshift" => make_native_fn(move |args: &[Value]| {
|
|
1823
|
+
arr_builtins::unshift(&Value::Array(a_clone.clone()), args)
|
|
1593
1824
|
}),
|
|
1594
|
-
"reverse" =>
|
|
1595
|
-
arr_builtins::reverse(&Value::Array(
|
|
1825
|
+
"reverse" => make_native_fn(move |_args: &[Value]| {
|
|
1826
|
+
arr_builtins::reverse(&Value::Array(a_clone.clone()))
|
|
1596
1827
|
}),
|
|
1597
|
-
"shuffle" =>
|
|
1598
|
-
arr_builtins::shuffle(&Value::Array(
|
|
1828
|
+
"shuffle" => make_native_fn(move |_args: &[Value]| {
|
|
1829
|
+
arr_builtins::shuffle(&Value::Array(a_clone.clone()))
|
|
1599
1830
|
}),
|
|
1600
|
-
"slice" =>
|
|
1831
|
+
"slice" => make_native_fn(move |args: &[Value]| {
|
|
1601
1832
|
let start = args.first().unwrap_or(&Value::Null);
|
|
1602
1833
|
let end = args.get(1).unwrap_or(&Value::Null);
|
|
1603
|
-
arr_builtins::slice(&Value::Array(
|
|
1834
|
+
arr_builtins::slice(&Value::Array(a_clone.clone()), start, end)
|
|
1604
1835
|
}),
|
|
1605
|
-
"concat" =>
|
|
1606
|
-
arr_builtins::concat(&Value::Array(
|
|
1836
|
+
"concat" => make_native_fn(move |args: &[Value]| {
|
|
1837
|
+
arr_builtins::concat(&Value::Array(a_clone.clone()), args)
|
|
1607
1838
|
}),
|
|
1608
|
-
"join" =>
|
|
1839
|
+
"join" => make_native_fn(move |args: &[Value]| {
|
|
1609
1840
|
let sep = args.first().unwrap_or(&Value::Null);
|
|
1610
|
-
arr_builtins::join(&Value::Array(
|
|
1841
|
+
arr_builtins::join(&Value::Array(a_clone.clone()), sep)
|
|
1611
1842
|
}),
|
|
1612
|
-
"indexOf" =>
|
|
1843
|
+
"indexOf" => make_native_fn(move |args: &[Value]| {
|
|
1613
1844
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1614
|
-
arr_builtins::index_of(&Value::Array(
|
|
1845
|
+
arr_builtins::index_of(&Value::Array(a_clone.clone()), search)
|
|
1615
1846
|
}),
|
|
1616
|
-
"includes" =>
|
|
1847
|
+
"includes" => make_native_fn(move |args: &[Value]| {
|
|
1617
1848
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1618
1849
|
let from = args.get(1);
|
|
1619
|
-
arr_builtins::includes(&Value::Array(
|
|
1850
|
+
arr_builtins::includes(&Value::Array(a_clone.clone()), search, from)
|
|
1620
1851
|
}),
|
|
1621
|
-
"map" =>
|
|
1852
|
+
"map" => make_native_fn(move |args: &[Value]| {
|
|
1622
1853
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1623
|
-
arr_builtins::map(&Value::Array(
|
|
1854
|
+
arr_builtins::map(&Value::Array(a_clone.clone()), &cb)
|
|
1624
1855
|
}),
|
|
1625
|
-
"filter" =>
|
|
1856
|
+
"filter" => make_native_fn(move |args: &[Value]| {
|
|
1626
1857
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1627
|
-
arr_builtins::filter(&Value::Array(
|
|
1858
|
+
arr_builtins::filter(&Value::Array(a_clone.clone()), &cb)
|
|
1628
1859
|
}),
|
|
1629
|
-
"reduce" =>
|
|
1860
|
+
"reduce" => make_native_fn(move |args: &[Value]| {
|
|
1630
1861
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1631
1862
|
let init = args.get(1).cloned().unwrap_or(Value::Null);
|
|
1632
|
-
arr_builtins::reduce(&Value::Array(
|
|
1863
|
+
arr_builtins::reduce(&Value::Array(a_clone.clone()), &cb, &init)
|
|
1633
1864
|
}),
|
|
1634
|
-
"forEach" =>
|
|
1865
|
+
"forEach" => make_native_fn(move |args: &[Value]| {
|
|
1635
1866
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1636
|
-
arr_builtins::for_each(&Value::Array(
|
|
1867
|
+
arr_builtins::for_each(&Value::Array(a_clone.clone()), &cb)
|
|
1637
1868
|
}),
|
|
1638
|
-
"find" =>
|
|
1869
|
+
"find" => make_native_fn(move |args: &[Value]| {
|
|
1639
1870
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1640
|
-
arr_builtins::find(&Value::Array(
|
|
1871
|
+
arr_builtins::find(&Value::Array(a_clone.clone()), &cb)
|
|
1641
1872
|
}),
|
|
1642
|
-
"findIndex" =>
|
|
1873
|
+
"findIndex" => make_native_fn(move |args: &[Value]| {
|
|
1643
1874
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1644
|
-
arr_builtins::find_index(&Value::Array(
|
|
1875
|
+
arr_builtins::find_index(&Value::Array(a_clone.clone()), &cb)
|
|
1645
1876
|
}),
|
|
1646
|
-
"some" =>
|
|
1877
|
+
"some" => make_native_fn(move |args: &[Value]| {
|
|
1647
1878
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1648
|
-
arr_builtins::some(&Value::Array(
|
|
1879
|
+
arr_builtins::some(&Value::Array(a_clone.clone()), &cb)
|
|
1649
1880
|
}),
|
|
1650
|
-
"every" =>
|
|
1881
|
+
"every" => make_native_fn(move |args: &[Value]| {
|
|
1651
1882
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1652
|
-
arr_builtins::every(&Value::Array(
|
|
1883
|
+
arr_builtins::every(&Value::Array(a_clone.clone()), &cb)
|
|
1653
1884
|
}),
|
|
1654
|
-
"flat" =>
|
|
1885
|
+
"flat" => make_native_fn(move |args: &[Value]| {
|
|
1655
1886
|
let depth = args.first().unwrap_or(&Value::Number(1.0));
|
|
1656
|
-
arr_builtins::flat(&Value::Array(
|
|
1887
|
+
arr_builtins::flat(&Value::Array(a_clone.clone()), depth)
|
|
1657
1888
|
}),
|
|
1658
|
-
"flatMap" =>
|
|
1889
|
+
"flatMap" => make_native_fn(move |args: &[Value]| {
|
|
1659
1890
|
let cb = args.first().cloned().unwrap_or(Value::Null);
|
|
1660
|
-
arr_builtins::flat_map(&Value::Array(
|
|
1891
|
+
arr_builtins::flat_map(&Value::Array(a_clone.clone()), &cb)
|
|
1661
1892
|
}),
|
|
1662
|
-
"sort" =>
|
|
1893
|
+
"sort" => make_native_fn(move |args: &[Value]| {
|
|
1663
1894
|
let cmp = args.first();
|
|
1664
1895
|
if let Some(Value::Function(_)) = cmp {
|
|
1665
1896
|
arr_builtins::sort_with_comparator(
|
|
1666
|
-
&Value::Array(
|
|
1897
|
+
&Value::Array(a_clone.clone()),
|
|
1667
1898
|
cmp.unwrap(),
|
|
1668
1899
|
)
|
|
1669
1900
|
} else {
|
|
1670
|
-
arr_builtins::sort_default(&Value::Array(
|
|
1901
|
+
arr_builtins::sort_default(&Value::Array(a_clone.clone()))
|
|
1671
1902
|
}
|
|
1672
1903
|
}),
|
|
1673
|
-
"splice" =>
|
|
1904
|
+
"splice" => make_native_fn(move |args: &[Value]| {
|
|
1674
1905
|
let start = args.first().unwrap_or(&Value::Null);
|
|
1675
1906
|
let delete_count = args.get(1).map(|v| v as &Value);
|
|
1676
1907
|
let items: Vec<Value> = args.get(2..).unwrap_or(&[]).to_vec();
|
|
1677
1908
|
arr_builtins::splice(
|
|
1678
|
-
&Value::Array(
|
|
1909
|
+
&Value::Array(a_clone.clone()),
|
|
1679
1910
|
start,
|
|
1680
1911
|
delete_count,
|
|
1681
1912
|
&items,
|
|
@@ -1698,12 +1929,12 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
1698
1929
|
}
|
|
1699
1930
|
let s_clone: Arc<str> = Arc::clone(s);
|
|
1700
1931
|
let method: ArrayMethodFn = match key_s {
|
|
1701
|
-
"indexOf" =>
|
|
1932
|
+
"indexOf" => make_native_fn(move |args: &[Value]| {
|
|
1702
1933
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1703
1934
|
let from = args.get(1);
|
|
1704
1935
|
str_builtins::index_of(&Value::String(Arc::clone(&s_clone)), search, from)
|
|
1705
1936
|
}),
|
|
1706
|
-
"lastIndexOf" =>
|
|
1937
|
+
"lastIndexOf" => make_native_fn(move |args: &[Value]| {
|
|
1707
1938
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1708
1939
|
let position = args.get(1).cloned().unwrap_or(Value::Number(f64::INFINITY));
|
|
1709
1940
|
str_builtins::last_index_of(
|
|
@@ -1712,48 +1943,48 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
1712
1943
|
&position,
|
|
1713
1944
|
)
|
|
1714
1945
|
}),
|
|
1715
|
-
"includes" =>
|
|
1946
|
+
"includes" => make_native_fn(move |args: &[Value]| {
|
|
1716
1947
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1717
1948
|
let from = args.get(1);
|
|
1718
1949
|
str_builtins::includes(&Value::String(Arc::clone(&s_clone)), search, from)
|
|
1719
1950
|
}),
|
|
1720
|
-
"slice" =>
|
|
1951
|
+
"slice" => make_native_fn(move |args: &[Value]| {
|
|
1721
1952
|
let start = args.first().unwrap_or(&Value::Null);
|
|
1722
1953
|
let end = args.get(1).unwrap_or(&Value::Null);
|
|
1723
1954
|
str_builtins::slice(&Value::String(Arc::clone(&s_clone)), start, end)
|
|
1724
1955
|
}),
|
|
1725
|
-
"substring" =>
|
|
1956
|
+
"substring" => make_native_fn(move |args: &[Value]| {
|
|
1726
1957
|
let start = args.first().unwrap_or(&Value::Null);
|
|
1727
1958
|
let end = args.get(1).unwrap_or(&Value::Null);
|
|
1728
1959
|
str_builtins::substring(&Value::String(Arc::clone(&s_clone)), start, end)
|
|
1729
1960
|
}),
|
|
1730
|
-
"split" =>
|
|
1961
|
+
"split" => make_native_fn(move |args: &[Value]| {
|
|
1731
1962
|
let sep = args.first().unwrap_or(&Value::Null);
|
|
1732
1963
|
str_builtins::split(&Value::String(Arc::clone(&s_clone)), sep)
|
|
1733
1964
|
}),
|
|
1734
|
-
"trim" =>
|
|
1965
|
+
"trim" => make_native_fn(move |_args: &[Value]| {
|
|
1735
1966
|
str_builtins::trim(&Value::String(Arc::clone(&s_clone)))
|
|
1736
1967
|
}),
|
|
1737
|
-
"toUpperCase" =>
|
|
1968
|
+
"toUpperCase" => make_native_fn(move |_args: &[Value]| {
|
|
1738
1969
|
str_builtins::to_upper_case(&Value::String(Arc::clone(&s_clone)))
|
|
1739
1970
|
}),
|
|
1740
|
-
"toLowerCase" =>
|
|
1971
|
+
"toLowerCase" => make_native_fn(move |_args: &[Value]| {
|
|
1741
1972
|
str_builtins::to_lower_case(&Value::String(Arc::clone(&s_clone)))
|
|
1742
1973
|
}),
|
|
1743
|
-
"startsWith" =>
|
|
1974
|
+
"startsWith" => make_native_fn(move |args: &[Value]| {
|
|
1744
1975
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1745
1976
|
str_builtins::starts_with(&Value::String(Arc::clone(&s_clone)), search)
|
|
1746
1977
|
}),
|
|
1747
|
-
"endsWith" =>
|
|
1978
|
+
"endsWith" => make_native_fn(move |args: &[Value]| {
|
|
1748
1979
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1749
1980
|
str_builtins::ends_with(&Value::String(Arc::clone(&s_clone)), search)
|
|
1750
1981
|
}),
|
|
1751
|
-
"replace" =>
|
|
1982
|
+
"replace" => make_native_fn(move |args: &[Value]| {
|
|
1752
1983
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1753
1984
|
let replacement = args.get(1).unwrap_or(&Value::Null);
|
|
1754
1985
|
str_builtins::replace(&Value::String(Arc::clone(&s_clone)), search, replacement)
|
|
1755
1986
|
}),
|
|
1756
|
-
"replaceAll" =>
|
|
1987
|
+
"replaceAll" => make_native_fn(move |args: &[Value]| {
|
|
1757
1988
|
let search = args.first().unwrap_or(&Value::Null);
|
|
1758
1989
|
let replacement = args.get(1).unwrap_or(&Value::Null);
|
|
1759
1990
|
str_builtins::replace_all(
|
|
@@ -1762,24 +1993,24 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
1762
1993
|
replacement,
|
|
1763
1994
|
)
|
|
1764
1995
|
}),
|
|
1765
|
-
"charAt" =>
|
|
1996
|
+
"charAt" => make_native_fn(move |args: &[Value]| {
|
|
1766
1997
|
let idx = args.first().unwrap_or(&Value::Null);
|
|
1767
1998
|
str_builtins::char_at(&Value::String(Arc::clone(&s_clone)), idx)
|
|
1768
1999
|
}),
|
|
1769
|
-
"charCodeAt" =>
|
|
2000
|
+
"charCodeAt" => make_native_fn(move |args: &[Value]| {
|
|
1770
2001
|
let idx = args.first().unwrap_or(&Value::Null);
|
|
1771
2002
|
str_builtins::char_code_at(&Value::String(Arc::clone(&s_clone)), idx)
|
|
1772
2003
|
}),
|
|
1773
|
-
"repeat" =>
|
|
2004
|
+
"repeat" => make_native_fn(move |args: &[Value]| {
|
|
1774
2005
|
let count = args.first().unwrap_or(&Value::Null);
|
|
1775
2006
|
str_builtins::repeat(&Value::String(Arc::clone(&s_clone)), count)
|
|
1776
2007
|
}),
|
|
1777
|
-
"padStart" =>
|
|
2008
|
+
"padStart" => make_native_fn(move |args: &[Value]| {
|
|
1778
2009
|
let target_len = args.first().unwrap_or(&Value::Null);
|
|
1779
2010
|
let pad = args.get(1).unwrap_or(&Value::Null);
|
|
1780
2011
|
str_builtins::pad_start(&Value::String(Arc::clone(&s_clone)), target_len, pad)
|
|
1781
2012
|
}),
|
|
1782
|
-
"padEnd" =>
|
|
2013
|
+
"padEnd" => make_native_fn(move |args: &[Value]| {
|
|
1783
2014
|
let target_len = args.first().unwrap_or(&Value::Null);
|
|
1784
2015
|
let pad = args.get(1).unwrap_or(&Value::Null);
|
|
1785
2016
|
str_builtins::pad_end(&Value::String(Arc::clone(&s_clone)), target_len, pad)
|
|
@@ -1788,6 +2019,22 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
|
|
|
1788
2019
|
};
|
|
1789
2020
|
Ok(Value::Function(method))
|
|
1790
2021
|
}
|
|
2022
|
+
#[cfg(feature = "http")]
|
|
2023
|
+
Value::Promise(p) => match key.as_ref() {
|
|
2024
|
+
"then" => {
|
|
2025
|
+
let pc = Arc::clone(p);
|
|
2026
|
+
Ok(Value::native(move |args| {
|
|
2027
|
+
tishlang_runtime::promise_instance_then(&pc, args)
|
|
2028
|
+
}))
|
|
2029
|
+
}
|
|
2030
|
+
"catch" => {
|
|
2031
|
+
let pc = Arc::clone(p);
|
|
2032
|
+
Ok(Value::native(move |args| {
|
|
2033
|
+
tishlang_runtime::promise_instance_catch(&pc, args)
|
|
2034
|
+
}))
|
|
2035
|
+
}
|
|
2036
|
+
_ => Err(format!("Property '{}' not found", key)),
|
|
2037
|
+
},
|
|
1791
2038
|
_ => Err(format!(
|
|
1792
2039
|
"Cannot read property '{}' of {}",
|
|
1793
2040
|
key,
|