@tishlang/tish 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +1 -0
- package/bin/tish +0 -0
- package/crates/js_to_tish/src/error.rs +2 -8
- package/crates/js_to_tish/src/transform/expr.rs +101 -130
- package/crates/js_to_tish/src/transform/stmt.rs +25 -22
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cli_help.rs +76 -29
- package/crates/tish/src/main.rs +85 -54
- package/crates/tish/tests/cargo_example_compile.rs +3 -1
- package/crates/tish/tests/integration_test.rs +197 -47
- package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
- package/crates/tish/tests/shortcircuit.rs +19 -4
- package/crates/tish_ast/src/ast.rs +12 -14
- package/crates/tish_build_utils/src/lib.rs +31 -6
- package/crates/tish_builtins/src/array.rs +52 -21
- package/crates/tish_builtins/src/construct.rs +2 -8
- package/crates/tish_builtins/src/globals.rs +30 -15
- package/crates/tish_builtins/src/lib.rs +5 -5
- package/crates/tish_builtins/src/math.rs +5 -3
- package/crates/tish_builtins/src/string.rs +71 -19
- package/crates/tish_bytecode/src/chunk.rs +0 -1
- package/crates/tish_bytecode/src/compiler.rs +164 -60
- package/crates/tish_bytecode/src/opcode.rs +13 -4
- package/crates/tish_bytecode/src/peephole.rs +2 -2
- package/crates/tish_compile/src/codegen.rs +921 -299
- package/crates/tish_compile/src/infer.rs +69 -19
- package/crates/tish_compile/src/lib.rs +15 -5
- package/crates/tish_compile/src/resolve.rs +112 -69
- package/crates/tish_compile/src/types.rs +10 -14
- package/crates/tish_compile_js/src/codegen.rs +34 -13
- package/crates/tish_compile_js/src/tests_jsx.rs +30 -6
- package/crates/tish_compiler_wasm/src/lib.rs +16 -13
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +39 -48
- package/crates/tish_core/src/json.rs +5 -3
- package/crates/tish_core/src/lib.rs +1 -1
- package/crates/tish_core/src/uri.rs +9 -6
- package/crates/tish_core/src/value.rs +92 -28
- package/crates/tish_cranelift/src/link.rs +6 -9
- package/crates/tish_cranelift/src/lower.rs +14 -8
- package/crates/tish_eval/src/eval.rs +389 -142
- package/crates/tish_eval/src/lib.rs +10 -6
- package/crates/tish_eval/src/natives.rs +95 -38
- package/crates/tish_eval/src/promise.rs +14 -8
- package/crates/tish_eval/src/timers.rs +28 -19
- package/crates/tish_eval/src/value.rs +10 -3
- package/crates/tish_fmt/src/lib.rs +29 -13
- package/crates/tish_lexer/src/lib.rs +217 -63
- package/crates/tish_lexer/src/token.rs +6 -6
- package/crates/tish_llvm/src/lib.rs +15 -8
- package/crates/tish_lsp/src/main.rs +41 -43
- package/crates/tish_native/src/build.rs +1 -6
- package/crates/tish_native/src/lib.rs +48 -19
- package/crates/tish_opt/src/lib.rs +67 -50
- package/crates/tish_parser/src/lib.rs +36 -11
- package/crates/tish_parser/src/parser.rs +172 -87
- package/crates/tish_runtime/src/http.rs +15 -6
- package/crates/tish_runtime/src/http_fetch.rs +24 -14
- package/crates/tish_runtime/src/lib.rs +224 -168
- package/crates/tish_runtime/src/promise.rs +1 -5
- package/crates/tish_runtime/src/ws.rs +45 -20
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
- package/crates/tish_ui/src/jsx.rs +41 -22
- package/crates/tish_ui/src/lib.rs +2 -2
- package/crates/tish_vm/src/vm.rs +309 -112
- package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +8 -3
- package/crates/tish_wasm/src/lib.rs +38 -28
- package/crates/tishlang_cargo_bindgen/Cargo.toml +25 -0
- package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
- package/crates/tishlang_cargo_bindgen/src/discover.rs +52 -0
- package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
- package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
- package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -0
- package/package.json +1 -1
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- package/platform/win32-x64/tish.exe +0 -0
|
@@ -8,11 +8,14 @@ use std::path::{Path, PathBuf};
|
|
|
8
8
|
use std::rc::Rc;
|
|
9
9
|
use std::sync::Arc;
|
|
10
10
|
|
|
11
|
-
use tishlang_ast::{
|
|
11
|
+
use tishlang_ast::{
|
|
12
|
+
BinOp, CompoundOp, ExportDeclaration, Expr, FunParam, ImportSpecifier, Literal,
|
|
13
|
+
LogicalAssignOp, MemberProp, Span, Statement, UnaryOp,
|
|
14
|
+
};
|
|
12
15
|
|
|
13
|
-
use crate::value::{PropMap, Value};
|
|
14
16
|
#[cfg(any(feature = "fs", feature = "process"))]
|
|
15
17
|
use crate::natives;
|
|
18
|
+
use crate::value::{PropMap, Value};
|
|
16
19
|
|
|
17
20
|
struct Scope {
|
|
18
21
|
vars: PropMap,
|
|
@@ -93,12 +96,24 @@ impl Evaluator {
|
|
|
93
96
|
console.insert("log".into(), Value::Native(natives::console_log));
|
|
94
97
|
console.insert("warn".into(), Value::Native(natives::console_warn));
|
|
95
98
|
console.insert("error".into(), Value::Native(natives::console_error));
|
|
96
|
-
s.set(
|
|
99
|
+
s.set(
|
|
100
|
+
"console".into(),
|
|
101
|
+
Value::Object(Rc::new(RefCell::new(console))),
|
|
102
|
+
true,
|
|
103
|
+
);
|
|
97
104
|
s.set("parseInt".into(), Value::Native(natives::parse_int), true);
|
|
98
|
-
s.set(
|
|
105
|
+
s.set(
|
|
106
|
+
"parseFloat".into(),
|
|
107
|
+
Value::Native(natives::parse_float),
|
|
108
|
+
true,
|
|
109
|
+
);
|
|
99
110
|
s.set("decodeURI".into(), Value::Native(natives::decode_uri), true);
|
|
100
111
|
s.set("encodeURI".into(), Value::Native(natives::encode_uri), true);
|
|
101
|
-
s.set(
|
|
112
|
+
s.set(
|
|
113
|
+
"Boolean".into(),
|
|
114
|
+
Value::Native(natives::boolean_native),
|
|
115
|
+
true,
|
|
116
|
+
);
|
|
102
117
|
s.set("isFinite".into(), Value::Native(natives::is_finite), true);
|
|
103
118
|
s.set("isNaN".into(), Value::Native(natives::is_nan), true);
|
|
104
119
|
s.set("Infinity".into(), Value::Number(f64::INFINITY), true);
|
|
@@ -122,32 +137,65 @@ impl Evaluator {
|
|
|
122
137
|
math.insert("trunc".into(), Value::Native(natives::math_trunc));
|
|
123
138
|
math.insert("PI".into(), Value::Number(std::f64::consts::PI));
|
|
124
139
|
math.insert("E".into(), Value::Number(std::f64::consts::E));
|
|
125
|
-
s.set(
|
|
140
|
+
s.set(
|
|
141
|
+
"Math".into(),
|
|
142
|
+
Value::Object(Rc::new(RefCell::new(math))),
|
|
143
|
+
true,
|
|
144
|
+
);
|
|
126
145
|
|
|
127
146
|
let mut json = PropMap::with_capacity(2);
|
|
128
147
|
json.insert("parse".into(), Value::Native(Self::json_parse_native));
|
|
129
|
-
json.insert(
|
|
130
|
-
|
|
148
|
+
json.insert(
|
|
149
|
+
"stringify".into(),
|
|
150
|
+
Value::Native(Self::json_stringify_native),
|
|
151
|
+
);
|
|
152
|
+
s.set(
|
|
153
|
+
"JSON".into(),
|
|
154
|
+
Value::Object(Rc::new(RefCell::new(json))),
|
|
155
|
+
true,
|
|
156
|
+
);
|
|
131
157
|
|
|
132
158
|
let mut object = PropMap::with_capacity(5);
|
|
133
159
|
object.insert("keys".into(), Value::Native(Self::object_keys));
|
|
134
160
|
object.insert("values".into(), Value::Native(Self::object_values));
|
|
135
161
|
object.insert("entries".into(), Value::Native(Self::object_entries));
|
|
136
162
|
object.insert("assign".into(), Value::Native(Self::object_assign));
|
|
137
|
-
object.insert(
|
|
138
|
-
|
|
163
|
+
object.insert(
|
|
164
|
+
"fromEntries".into(),
|
|
165
|
+
Value::Native(Self::object_from_entries),
|
|
166
|
+
);
|
|
167
|
+
s.set(
|
|
168
|
+
"Object".into(),
|
|
169
|
+
Value::Object(Rc::new(RefCell::new(object))),
|
|
170
|
+
true,
|
|
171
|
+
);
|
|
139
172
|
|
|
140
173
|
let mut array_obj = PropMap::with_capacity(1);
|
|
141
174
|
array_obj.insert("isArray".into(), Value::Native(natives::array_is_array));
|
|
142
|
-
s.set(
|
|
175
|
+
s.set(
|
|
176
|
+
"Array".into(),
|
|
177
|
+
Value::Object(Rc::new(RefCell::new(array_obj))),
|
|
178
|
+
true,
|
|
179
|
+
);
|
|
143
180
|
|
|
144
181
|
let mut string_obj = PropMap::with_capacity(1);
|
|
145
|
-
string_obj.insert(
|
|
146
|
-
|
|
182
|
+
string_obj.insert(
|
|
183
|
+
"fromCharCode".into(),
|
|
184
|
+
Value::Native(natives::string_from_char_code),
|
|
185
|
+
);
|
|
186
|
+
s.set(
|
|
187
|
+
"String".into(),
|
|
188
|
+
Value::Object(Rc::new(RefCell::new(string_obj))),
|
|
189
|
+
true,
|
|
190
|
+
);
|
|
147
191
|
|
|
148
192
|
let mut date = PropMap::with_capacity(1);
|
|
149
193
|
date.insert("now".into(), Value::Native(natives::date_now));
|
|
150
|
-
s.set(
|
|
194
|
+
s.set(
|
|
195
|
+
"Date".into(),
|
|
196
|
+
Value::Object(Rc::new(RefCell::new(date))),
|
|
197
|
+
true,
|
|
198
|
+
);
|
|
151
199
|
|
|
152
200
|
s.set(
|
|
153
201
|
"Uint8Array".into(),
|
|
@@ -166,7 +214,11 @@ impl Evaluator {
|
|
|
166
214
|
|
|
167
215
|
#[cfg(feature = "regex")]
|
|
168
216
|
{
|
|
169
|
-
s.set(
|
|
217
|
+
s.set(
|
|
218
|
+
"RegExp".into(),
|
|
219
|
+
Value::Native(Self::regexp_constructor_native),
|
|
220
|
+
true,
|
|
221
|
+
);
|
|
170
222
|
}
|
|
171
223
|
|
|
172
224
|
// fs, http, process: use import { x } from 'tish:fs' etc. No globals.
|
|
@@ -225,16 +277,28 @@ impl Evaluator {
|
|
|
225
277
|
self.scope = prev;
|
|
226
278
|
Ok(last)
|
|
227
279
|
}
|
|
228
|
-
Statement::VarDecl {
|
|
280
|
+
Statement::VarDecl {
|
|
281
|
+
name,
|
|
282
|
+
mutable,
|
|
283
|
+
init,
|
|
284
|
+
..
|
|
285
|
+
} => {
|
|
229
286
|
let value = init
|
|
230
287
|
.as_ref()
|
|
231
288
|
.map(|e| self.eval_expr(e))
|
|
232
289
|
.transpose()?
|
|
233
290
|
.unwrap_or(Value::Null);
|
|
234
|
-
self.scope
|
|
291
|
+
self.scope
|
|
292
|
+
.borrow_mut()
|
|
293
|
+
.set(Arc::clone(name), value, *mutable);
|
|
235
294
|
Ok(Value::Null)
|
|
236
295
|
}
|
|
237
|
-
Statement::VarDeclDestructure {
|
|
296
|
+
Statement::VarDeclDestructure {
|
|
297
|
+
pattern,
|
|
298
|
+
mutable,
|
|
299
|
+
init,
|
|
300
|
+
..
|
|
301
|
+
} => {
|
|
238
302
|
let value = self.eval_expr(init)?;
|
|
239
303
|
self.bind_destruct_pattern(pattern, &value, *mutable)?;
|
|
240
304
|
Ok(Value::Null)
|
|
@@ -269,15 +333,21 @@ impl Evaluator {
|
|
|
269
333
|
}
|
|
270
334
|
Ok(Value::Null)
|
|
271
335
|
}
|
|
272
|
-
Statement::ForOf {
|
|
336
|
+
Statement::ForOf {
|
|
337
|
+
name,
|
|
338
|
+
iterable,
|
|
339
|
+
body,
|
|
340
|
+
..
|
|
341
|
+
} => {
|
|
273
342
|
let iter_val = self.eval_expr(iterable)?;
|
|
274
343
|
let elements = match &iter_val {
|
|
275
|
-
crate::value::Value::Array(arr) =>
|
|
276
|
-
|
|
277
|
-
s.chars()
|
|
278
|
-
.map(|c| crate::value::Value::String(Arc::from(c.to_string())))
|
|
279
|
-
.collect::<Vec<_>>()
|
|
344
|
+
crate::value::Value::Array(arr) => {
|
|
345
|
+
arr.borrow().iter().cloned().collect::<Vec<_>>()
|
|
280
346
|
}
|
|
347
|
+
crate::value::Value::String(s) => s
|
|
348
|
+
.chars()
|
|
349
|
+
.map(|c| crate::value::Value::String(Arc::from(c.to_string())))
|
|
350
|
+
.collect::<Vec<_>>(),
|
|
281
351
|
_ => {
|
|
282
352
|
return Err(EvalError::Error(format!(
|
|
283
353
|
"for-of requires iterable (array or string), got {}",
|
|
@@ -360,7 +430,12 @@ impl Evaluator {
|
|
|
360
430
|
self.scope.borrow_mut().set(Arc::clone(name), func, true);
|
|
361
431
|
Ok(Value::Null)
|
|
362
432
|
}
|
|
363
|
-
Statement::Switch {
|
|
433
|
+
Statement::Switch {
|
|
434
|
+
expr,
|
|
435
|
+
cases,
|
|
436
|
+
default_body,
|
|
437
|
+
..
|
|
438
|
+
} => {
|
|
364
439
|
let v = self.eval_expr(expr)?;
|
|
365
440
|
let mut matched = false;
|
|
366
441
|
for (case_expr, body) in cases {
|
|
@@ -438,7 +513,7 @@ impl Evaluator {
|
|
|
438
513
|
..
|
|
439
514
|
} => {
|
|
440
515
|
let try_result = self.eval_statement(body);
|
|
441
|
-
|
|
516
|
+
|
|
442
517
|
let result = match try_result {
|
|
443
518
|
Ok(v) => Ok(v),
|
|
444
519
|
Err(EvalError::Throw(thrown)) => {
|
|
@@ -459,18 +534,24 @@ impl Evaluator {
|
|
|
459
534
|
}
|
|
460
535
|
Err(e) => Err(e),
|
|
461
536
|
};
|
|
462
|
-
|
|
537
|
+
|
|
463
538
|
if let Some(finally_stmt) = finally_body {
|
|
464
539
|
let _ = self.eval_statement(finally_stmt);
|
|
465
540
|
}
|
|
466
|
-
|
|
541
|
+
|
|
467
542
|
result
|
|
468
543
|
}
|
|
469
|
-
Statement::Import {
|
|
544
|
+
Statement::Import {
|
|
545
|
+
specifiers, from, ..
|
|
546
|
+
} => {
|
|
470
547
|
let exports_val = self.load_module(from)?;
|
|
471
548
|
let exports = match &exports_val {
|
|
472
549
|
Value::Object(m) => m.borrow().clone(),
|
|
473
|
-
_ =>
|
|
550
|
+
_ => {
|
|
551
|
+
return Err(EvalError::Error(
|
|
552
|
+
"Module exports must be object".to_string(),
|
|
553
|
+
))
|
|
554
|
+
}
|
|
474
555
|
};
|
|
475
556
|
let mut scope = self.scope.borrow_mut();
|
|
476
557
|
for spec in specifiers {
|
|
@@ -514,7 +595,8 @@ impl Evaluator {
|
|
|
514
595
|
fn load_module(&mut self, from: &str) -> Result<Value, EvalError> {
|
|
515
596
|
if from.starts_with("cargo:") {
|
|
516
597
|
return Err(EvalError::Error(
|
|
517
|
-
"cargo:… imports are only supported by `tish build` with the Rust native backend."
|
|
598
|
+
"cargo:… imports are only supported by `tish build` with the Rust native backend."
|
|
599
|
+
.into(),
|
|
518
600
|
));
|
|
519
601
|
}
|
|
520
602
|
if from.starts_with("tish:") {
|
|
@@ -525,24 +607,24 @@ impl Evaluator {
|
|
|
525
607
|
return self.load_builtin_module(from);
|
|
526
608
|
}
|
|
527
609
|
let dir = self.current_dir.borrow().clone().ok_or_else(|| {
|
|
528
|
-
EvalError::Error(
|
|
610
|
+
EvalError::Error(
|
|
611
|
+
"Cannot resolve imports: no current file directory (use run_file)".to_string(),
|
|
612
|
+
)
|
|
529
613
|
})?;
|
|
530
614
|
let path = Self::resolve_import_path(from, &dir)?;
|
|
531
|
-
let path = path
|
|
532
|
-
|
|
533
|
-
|
|
615
|
+
let path = path
|
|
616
|
+
.canonicalize()
|
|
617
|
+
.map_err(|e| EvalError::Error(format!("Cannot resolve import '{}': {}", from, e)))?;
|
|
534
618
|
{
|
|
535
619
|
let cache = self.module_cache.borrow();
|
|
536
620
|
if let Some(m) = cache.get(&path) {
|
|
537
621
|
return Ok(m.clone());
|
|
538
622
|
}
|
|
539
623
|
}
|
|
540
|
-
let source = std::fs::read_to_string(&path)
|
|
541
|
-
EvalError::Error(format!("Cannot read {}: {}", path.display(), e))
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
EvalError::Error(format!("Parse error in {}: {}", path.display(), e))
|
|
545
|
-
})?;
|
|
624
|
+
let source = std::fs::read_to_string(&path)
|
|
625
|
+
.map_err(|e| EvalError::Error(format!("Cannot read {}: {}", path.display(), e)))?;
|
|
626
|
+
let program = tishlang_parser::parse(&source)
|
|
627
|
+
.map_err(|e| EvalError::Error(format!("Parse error in {}: {}", path.display(), e)))?;
|
|
546
628
|
let module_scope = Scope::child(Rc::clone(&self.scope));
|
|
547
629
|
let prev_scope = std::mem::replace(&mut self.scope, Rc::clone(&module_scope));
|
|
548
630
|
let parent_dir = self.current_dir.borrow().clone();
|
|
@@ -554,7 +636,9 @@ impl Evaluator {
|
|
|
554
636
|
match declaration.as_ref() {
|
|
555
637
|
ExportDeclaration::Named(s) => {
|
|
556
638
|
let _ = self.eval_statement(s);
|
|
557
|
-
if let Statement::VarDecl { name, .. } | Statement::FunDecl { name, .. } =
|
|
639
|
+
if let Statement::VarDecl { name, .. } | Statement::FunDecl { name, .. } =
|
|
640
|
+
s.as_ref()
|
|
641
|
+
{
|
|
558
642
|
export_names.push(name.to_string());
|
|
559
643
|
}
|
|
560
644
|
}
|
|
@@ -577,7 +661,9 @@ impl Evaluator {
|
|
|
577
661
|
*self.current_dir.borrow_mut() = parent_dir;
|
|
578
662
|
self.scope = prev_scope;
|
|
579
663
|
let exports_val = Value::Object(Rc::new(RefCell::new(exports)));
|
|
580
|
-
self.module_cache
|
|
664
|
+
self.module_cache
|
|
665
|
+
.borrow_mut()
|
|
666
|
+
.insert(path, exports_val.clone());
|
|
581
667
|
Ok(exports_val)
|
|
582
668
|
}
|
|
583
669
|
|
|
@@ -640,10 +726,22 @@ impl Evaluator {
|
|
|
640
726
|
exports.insert("fetchAll".into(), Value::Native(Self::fetch_all_native));
|
|
641
727
|
exports.insert("serve".into(), Value::Serve);
|
|
642
728
|
exports.insert("Promise".into(), Value::PromiseConstructor);
|
|
643
|
-
exports.insert(
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
729
|
+
exports.insert(
|
|
730
|
+
"setTimeout".into(),
|
|
731
|
+
Value::TimerBuiltin(Arc::from("setTimeout")),
|
|
732
|
+
);
|
|
733
|
+
exports.insert(
|
|
734
|
+
"setInterval".into(),
|
|
735
|
+
Value::TimerBuiltin(Arc::from("setInterval")),
|
|
736
|
+
);
|
|
737
|
+
exports.insert(
|
|
738
|
+
"clearTimeout".into(),
|
|
739
|
+
Value::Native(Self::clear_timeout_native),
|
|
740
|
+
);
|
|
741
|
+
exports.insert(
|
|
742
|
+
"clearInterval".into(),
|
|
743
|
+
Value::Native(Self::clear_interval_native),
|
|
744
|
+
);
|
|
647
745
|
return Ok(Value::Object(Rc::new(RefCell::new(exports))));
|
|
648
746
|
}
|
|
649
747
|
#[cfg(not(feature = "http"))]
|
|
@@ -657,10 +755,16 @@ impl Evaluator {
|
|
|
657
755
|
#[cfg(feature = "ws")]
|
|
658
756
|
{
|
|
659
757
|
let mut exports: PropMap = PropMap::default();
|
|
660
|
-
exports.insert(
|
|
758
|
+
exports.insert(
|
|
759
|
+
"WebSocket".into(),
|
|
760
|
+
Value::Native(Self::ws_web_socket_native),
|
|
761
|
+
);
|
|
661
762
|
exports.insert("Server".into(), Value::Native(Self::ws_server_native));
|
|
662
763
|
exports.insert("wsSend".into(), Value::Native(Self::ws_send_native));
|
|
663
|
-
exports.insert(
|
|
764
|
+
exports.insert(
|
|
765
|
+
"wsBroadcast".into(),
|
|
766
|
+
Value::Native(Self::ws_broadcast_native),
|
|
767
|
+
);
|
|
664
768
|
return Ok(Value::Object(Rc::new(RefCell::new(exports))));
|
|
665
769
|
}
|
|
666
770
|
#[cfg(not(feature = "ws"))]
|
|
@@ -677,21 +781,29 @@ impl Evaluator {
|
|
|
677
781
|
exports.insert("exit".into(), Value::Native(natives::process_exit));
|
|
678
782
|
exports.insert("cwd".into(), Value::Native(natives::process_cwd));
|
|
679
783
|
exports.insert("exec".into(), Value::Native(natives::process_exec));
|
|
680
|
-
let argv: Vec<Value> =
|
|
681
|
-
.map(|s| Value::String(s.into()))
|
|
682
|
-
|
|
683
|
-
|
|
784
|
+
let argv: Vec<Value> =
|
|
785
|
+
std::env::args().map(|s| Value::String(s.into())).collect();
|
|
786
|
+
exports.insert(
|
|
787
|
+
"argv".into(),
|
|
788
|
+
Value::Array(Rc::new(RefCell::new(argv.clone()))),
|
|
789
|
+
);
|
|
684
790
|
let env_obj: PropMap = std::env::vars()
|
|
685
791
|
.map(|(key, value)| (Arc::from(key.as_str()), Value::String(value.into())))
|
|
686
792
|
.collect();
|
|
687
|
-
exports.insert(
|
|
793
|
+
exports.insert(
|
|
794
|
+
"env".into(),
|
|
795
|
+
Value::Object(Rc::new(RefCell::new(env_obj.clone()))),
|
|
796
|
+
);
|
|
688
797
|
let mut process_obj = PropMap::default();
|
|
689
798
|
process_obj.insert("exit".into(), Value::Native(natives::process_exit));
|
|
690
799
|
process_obj.insert("cwd".into(), Value::Native(natives::process_cwd));
|
|
691
800
|
process_obj.insert("exec".into(), Value::Native(natives::process_exec));
|
|
692
801
|
process_obj.insert("argv".into(), Value::Array(Rc::new(RefCell::new(argv))));
|
|
693
802
|
process_obj.insert("env".into(), Value::Object(Rc::new(RefCell::new(env_obj))));
|
|
694
|
-
exports.insert(
|
|
803
|
+
exports.insert(
|
|
804
|
+
"process".into(),
|
|
805
|
+
Value::Object(Rc::new(RefCell::new(process_obj))),
|
|
806
|
+
);
|
|
695
807
|
return Ok(Value::Object(Rc::new(RefCell::new(exports))));
|
|
696
808
|
}
|
|
697
809
|
#[cfg(not(feature = "process"))]
|
|
@@ -1912,7 +2024,13 @@ impl Evaluator {
|
|
|
1912
2024
|
/// descending = false: checks for `(a, b) => a - b`
|
|
1913
2025
|
/// descending = true: checks for `(a, b) => b - a`
|
|
1914
2026
|
fn is_numeric_sort_comparator(f: &Value, descending: bool) -> bool {
|
|
1915
|
-
if let Value::Function {
|
|
2027
|
+
if let Value::Function {
|
|
2028
|
+
formals,
|
|
2029
|
+
body,
|
|
2030
|
+
rest_param,
|
|
2031
|
+
..
|
|
2032
|
+
} = f
|
|
2033
|
+
{
|
|
1916
2034
|
// Must have exactly 2 simple params, no defaults, no rest
|
|
1917
2035
|
if formals.len() != 2 || rest_param.is_some() {
|
|
1918
2036
|
return false;
|
|
@@ -1936,15 +2054,29 @@ impl Evaluator {
|
|
|
1936
2054
|
};
|
|
1937
2055
|
|
|
1938
2056
|
// Check for binary subtraction
|
|
1939
|
-
if let Expr::Binary {
|
|
2057
|
+
if let Expr::Binary {
|
|
2058
|
+
left,
|
|
2059
|
+
op: BinOp::Sub,
|
|
2060
|
+
right,
|
|
2061
|
+
..
|
|
2062
|
+
} = expr
|
|
2063
|
+
{
|
|
1940
2064
|
// Check left is Ident(a) and right is Ident(b)
|
|
1941
2065
|
let (expected_left, expected_right) = if descending {
|
|
1942
|
-
(param_b, param_a)
|
|
2066
|
+
(param_b, param_a) // b - a
|
|
1943
2067
|
} else {
|
|
1944
|
-
(param_a, param_b)
|
|
2068
|
+
(param_a, param_b) // a - b
|
|
1945
2069
|
};
|
|
1946
2070
|
|
|
1947
|
-
if let (
|
|
2071
|
+
if let (
|
|
2072
|
+
Expr::Ident {
|
|
2073
|
+
name: left_name, ..
|
|
2074
|
+
},
|
|
2075
|
+
Expr::Ident {
|
|
2076
|
+
name: right_name, ..
|
|
2077
|
+
},
|
|
2078
|
+
) = (left.as_ref(), right.as_ref())
|
|
2079
|
+
{
|
|
1948
2080
|
return left_name == expected_left && right_name == expected_right;
|
|
1949
2081
|
}
|
|
1950
2082
|
}
|
|
@@ -1999,8 +2131,17 @@ impl Evaluator {
|
|
|
1999
2131
|
|
|
2000
2132
|
/// Optimized callback invocation for array methods.
|
|
2001
2133
|
/// Creates a reusable scope that can be updated for each iteration.
|
|
2002
|
-
fn create_callback_scope(
|
|
2003
|
-
|
|
2134
|
+
fn create_callback_scope(
|
|
2135
|
+
&self,
|
|
2136
|
+
f: &Value,
|
|
2137
|
+
) -> Option<(Rc<RefCell<Scope>>, Arc<[Arc<str>]>, Arc<Statement>)> {
|
|
2138
|
+
if let Value::Function {
|
|
2139
|
+
formals,
|
|
2140
|
+
body,
|
|
2141
|
+
rest_param,
|
|
2142
|
+
..
|
|
2143
|
+
} = f
|
|
2144
|
+
{
|
|
2004
2145
|
if rest_param.is_some() {
|
|
2005
2146
|
return None;
|
|
2006
2147
|
}
|
|
@@ -2063,12 +2204,14 @@ impl Evaluator {
|
|
|
2063
2204
|
|
|
2064
2205
|
/// Try to evaluate a simple callback expression directly without creating a scope.
|
|
2065
2206
|
/// Returns Some(result) for simple patterns like `x => x * 2` or `x => x > 5`.
|
|
2066
|
-
fn eval_simple_callback(
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2207
|
+
fn eval_simple_callback(&self, f: &Value, args: &[Value]) -> Option<Result<Value, EvalError>> {
|
|
2208
|
+
if let Value::Function {
|
|
2209
|
+
formals,
|
|
2210
|
+
body,
|
|
2211
|
+
rest_param,
|
|
2212
|
+
..
|
|
2213
|
+
} = f
|
|
2214
|
+
{
|
|
2072
2215
|
if formals.len() != 1 || rest_param.is_some() {
|
|
2073
2216
|
return None;
|
|
2074
2217
|
}
|
|
@@ -2088,17 +2231,25 @@ impl Evaluator {
|
|
|
2088
2231
|
// Fast path for common patterns
|
|
2089
2232
|
match expr {
|
|
2090
2233
|
// x * constant or x + constant, etc.
|
|
2091
|
-
Expr::Binary {
|
|
2234
|
+
Expr::Binary {
|
|
2235
|
+
left, op, right, ..
|
|
2236
|
+
} => {
|
|
2092
2237
|
let left_val = self.eval_simple_operand(left, param_name, &arg)?;
|
|
2093
2238
|
let right_val = self.eval_simple_operand(right, param_name, &arg)?;
|
|
2094
|
-
Some(
|
|
2239
|
+
Some(
|
|
2240
|
+
self.eval_binop(&left_val, *op, &right_val)
|
|
2241
|
+
.map_err(EvalError::Error),
|
|
2242
|
+
)
|
|
2095
2243
|
}
|
|
2096
2244
|
// Just return the parameter
|
|
2097
|
-
Expr::Ident { name, .. } if name == param_name =>
|
|
2098
|
-
Some(Ok(arg))
|
|
2099
|
-
}
|
|
2245
|
+
Expr::Ident { name, .. } if name == param_name => Some(Ok(arg)),
|
|
2100
2246
|
// Property access: x.prop
|
|
2101
|
-
Expr::Member {
|
|
2247
|
+
Expr::Member {
|
|
2248
|
+
object,
|
|
2249
|
+
prop,
|
|
2250
|
+
optional,
|
|
2251
|
+
..
|
|
2252
|
+
} => {
|
|
2102
2253
|
if let Expr::Ident { name, .. } = object.as_ref() {
|
|
2103
2254
|
if name == param_name {
|
|
2104
2255
|
return self.eval_simple_member(&arg, prop, *optional);
|
|
@@ -2114,7 +2265,12 @@ impl Evaluator {
|
|
|
2114
2265
|
}
|
|
2115
2266
|
|
|
2116
2267
|
/// Evaluate a simple operand (identifier or literal).
|
|
2117
|
-
fn eval_simple_operand(
|
|
2268
|
+
fn eval_simple_operand(
|
|
2269
|
+
&self,
|
|
2270
|
+
expr: &Expr,
|
|
2271
|
+
param_name: &Arc<str>,
|
|
2272
|
+
param_val: &Value,
|
|
2273
|
+
) -> Option<Value> {
|
|
2118
2274
|
match expr {
|
|
2119
2275
|
Expr::Ident { name, .. } if name == param_name => Some(param_val.clone()),
|
|
2120
2276
|
Expr::Literal { value, .. } => match value {
|
|
@@ -2128,20 +2284,27 @@ impl Evaluator {
|
|
|
2128
2284
|
}
|
|
2129
2285
|
|
|
2130
2286
|
/// Evaluate simple member access.
|
|
2131
|
-
fn eval_simple_member(
|
|
2287
|
+
fn eval_simple_member(
|
|
2288
|
+
&self,
|
|
2289
|
+
obj: &Value,
|
|
2290
|
+
property: &MemberProp,
|
|
2291
|
+
_optional: bool,
|
|
2292
|
+
) -> Option<Result<Value, EvalError>> {
|
|
2132
2293
|
match property {
|
|
2133
|
-
MemberProp::Name(name) => {
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2294
|
+
MemberProp::Name(name) => match obj {
|
|
2295
|
+
Value::Object(o) => {
|
|
2296
|
+
let result = o
|
|
2297
|
+
.borrow()
|
|
2298
|
+
.get(name.as_ref())
|
|
2299
|
+
.cloned()
|
|
2300
|
+
.unwrap_or(Value::Null);
|
|
2301
|
+
Some(Ok(result))
|
|
2302
|
+
}
|
|
2303
|
+
Value::Array(arr) if name.as_ref() == "length" => {
|
|
2304
|
+
Some(Ok(Value::Number(arr.borrow().len() as f64)))
|
|
2143
2305
|
}
|
|
2144
|
-
|
|
2306
|
+
_ => None,
|
|
2307
|
+
},
|
|
2145
2308
|
_ => None,
|
|
2146
2309
|
}
|
|
2147
2310
|
}
|
|
@@ -2169,9 +2332,7 @@ impl Evaluator {
|
|
|
2169
2332
|
|
|
2170
2333
|
fn call_func(&self, f: &Value, args: &[Value]) -> Result<Value, EvalError> {
|
|
2171
2334
|
match f {
|
|
2172
|
-
Value::Native(native_fn) =>
|
|
2173
|
-
native_fn(args).map_err(EvalError::Error)
|
|
2174
|
-
}
|
|
2335
|
+
Value::Native(native_fn) => native_fn(args).map_err(EvalError::Error),
|
|
2175
2336
|
#[cfg(feature = "http")]
|
|
2176
2337
|
Value::PromiseResolver(r) => {
|
|
2177
2338
|
let value = args.first().cloned().unwrap_or(Value::Null);
|
|
@@ -2180,7 +2341,12 @@ impl Evaluator {
|
|
|
2180
2341
|
.map_err(EvalError::Error)?;
|
|
2181
2342
|
for reaction in reactions {
|
|
2182
2343
|
match reaction {
|
|
2183
|
-
crate::promise::Reaction::Then(
|
|
2344
|
+
crate::promise::Reaction::Then(
|
|
2345
|
+
on_fulfilled,
|
|
2346
|
+
on_rejected,
|
|
2347
|
+
ref resolve,
|
|
2348
|
+
ref reject,
|
|
2349
|
+
) => {
|
|
2184
2350
|
let handler_result = if is_fulfilled {
|
|
2185
2351
|
if let Some(ref h) = on_fulfilled {
|
|
2186
2352
|
self.call_func(h, &[val.clone()])
|
|
@@ -2232,8 +2398,10 @@ impl Evaluator {
|
|
|
2232
2398
|
#[cfg(feature = "http")]
|
|
2233
2399
|
Value::Serve => self.run_http_server(args),
|
|
2234
2400
|
Value::CoreFn(f) => {
|
|
2235
|
-
let ca: Result<Vec<tishlang_core::Value>, String> =
|
|
2236
|
-
|
|
2401
|
+
let ca: Result<Vec<tishlang_core::Value>, String> = args
|
|
2402
|
+
.iter()
|
|
2403
|
+
.map(crate::value_convert::eval_to_core)
|
|
2404
|
+
.collect();
|
|
2237
2405
|
let ca = ca.map_err(EvalError::Error)?;
|
|
2238
2406
|
Ok(crate::value_convert::core_to_eval(f(&ca)))
|
|
2239
2407
|
}
|
|
@@ -2247,15 +2415,25 @@ impl Evaluator {
|
|
|
2247
2415
|
Value::TimerBuiltin(name) => self.run_timer_builtin(name.as_ref(), args),
|
|
2248
2416
|
Value::OpaqueMethod(opaque, method_name) => {
|
|
2249
2417
|
let method = opaque.get_method(method_name.as_ref()).ok_or_else(|| {
|
|
2250
|
-
EvalError::Error(format!(
|
|
2418
|
+
EvalError::Error(format!(
|
|
2419
|
+
"Method {} not found on {}",
|
|
2420
|
+
method_name,
|
|
2421
|
+
opaque.type_name()
|
|
2422
|
+
))
|
|
2251
2423
|
})?;
|
|
2252
|
-
let core_args: Result<Vec<tishlang_core::Value>, String> =
|
|
2253
|
-
|
|
2424
|
+
let core_args: Result<Vec<tishlang_core::Value>, String> = args
|
|
2425
|
+
.iter()
|
|
2426
|
+
.map(crate::value_convert::eval_to_core)
|
|
2427
|
+
.collect();
|
|
2254
2428
|
let core_args = core_args.map_err(EvalError::Error)?;
|
|
2255
2429
|
let result = method(&core_args);
|
|
2256
2430
|
Ok(crate::value_convert::core_to_eval(result))
|
|
2257
2431
|
}
|
|
2258
|
-
Value::Function {
|
|
2432
|
+
Value::Function {
|
|
2433
|
+
formals,
|
|
2434
|
+
rest_param,
|
|
2435
|
+
body,
|
|
2436
|
+
} => {
|
|
2259
2437
|
let scope = Scope::child(Rc::clone(&self.scope));
|
|
2260
2438
|
{
|
|
2261
2439
|
let mut s = scope.borrow_mut();
|
|
@@ -2289,8 +2467,13 @@ impl Evaluator {
|
|
|
2289
2467
|
}
|
|
2290
2468
|
}
|
|
2291
2469
|
if let Some(ref rest_name) = rest_param {
|
|
2292
|
-
let rest_vals: Vec<Value> =
|
|
2293
|
-
|
|
2470
|
+
let rest_vals: Vec<Value> =
|
|
2471
|
+
args.iter().skip(formals.len()).cloned().collect();
|
|
2472
|
+
s.set(
|
|
2473
|
+
Arc::clone(rest_name),
|
|
2474
|
+
Value::Array(Rc::new(RefCell::new(rest_vals))),
|
|
2475
|
+
true,
|
|
2476
|
+
);
|
|
2294
2477
|
}
|
|
2295
2478
|
}
|
|
2296
2479
|
let mut eval = Evaluator {
|
|
@@ -2304,8 +2487,12 @@ impl Evaluator {
|
|
|
2304
2487
|
Err(EvalError::Return(v)) => Ok(v),
|
|
2305
2488
|
Err(EvalError::Throw(v)) => Err(EvalError::Throw(v)),
|
|
2306
2489
|
Err(EvalError::Error(s)) => Err(EvalError::Error(s)),
|
|
2307
|
-
Err(EvalError::Break) =>
|
|
2308
|
-
|
|
2490
|
+
Err(EvalError::Break) => {
|
|
2491
|
+
Err(EvalError::Error("break outside loop".to_string()))
|
|
2492
|
+
}
|
|
2493
|
+
Err(EvalError::Continue) => {
|
|
2494
|
+
Err(EvalError::Error("continue outside loop".to_string()))
|
|
2495
|
+
}
|
|
2309
2496
|
}
|
|
2310
2497
|
}
|
|
2311
2498
|
_ => Err(EvalError::Error("Not a function".to_string())),
|
|
@@ -2320,14 +2507,15 @@ impl Evaluator {
|
|
|
2320
2507
|
args: &[Value],
|
|
2321
2508
|
) -> Result<Value, EvalError> {
|
|
2322
2509
|
match method {
|
|
2323
|
-
"then" =>
|
|
2324
|
-
promise_ref,
|
|
2325
|
-
|
|
2326
|
-
args.get(1).cloned(),
|
|
2327
|
-
),
|
|
2510
|
+
"then" => {
|
|
2511
|
+
self.run_promise_then_core(promise_ref, args.first().cloned(), args.get(1).cloned())
|
|
2512
|
+
}
|
|
2328
2513
|
"catch" => self.run_promise_then_core(promise_ref, None, args.first().cloned()),
|
|
2329
2514
|
"finally" => self.run_promise_finally(promise_ref, args.first().cloned()),
|
|
2330
|
-
_ => Err(EvalError::Error(format!(
|
|
2515
|
+
_ => Err(EvalError::Error(format!(
|
|
2516
|
+
"Unknown promise method: {}",
|
|
2517
|
+
method
|
|
2518
|
+
))),
|
|
2331
2519
|
}
|
|
2332
2520
|
}
|
|
2333
2521
|
|
|
@@ -2428,7 +2616,12 @@ impl Evaluator {
|
|
|
2428
2616
|
crate::promise::PromiseState::Pending { .. } => {
|
|
2429
2617
|
crate::promise::add_reaction(
|
|
2430
2618
|
state,
|
|
2431
|
-
crate::promise::Reaction::Then(
|
|
2619
|
+
crate::promise::Reaction::Then(
|
|
2620
|
+
on_fulfilled,
|
|
2621
|
+
on_rejected,
|
|
2622
|
+
resolve.clone(),
|
|
2623
|
+
reject.clone(),
|
|
2624
|
+
),
|
|
2432
2625
|
);
|
|
2433
2626
|
}
|
|
2434
2627
|
}
|
|
@@ -2537,8 +2730,11 @@ impl Evaluator {
|
|
|
2537
2730
|
let port = port;
|
|
2538
2731
|
std::thread::spawn(move || {
|
|
2539
2732
|
std::thread::sleep(std::time::Duration::from_millis(50));
|
|
2540
|
-
if let Ok(mut stream) = std::net::TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
2541
|
-
|
|
2733
|
+
if let Ok(mut stream) = std::net::TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
2734
|
+
{
|
|
2735
|
+
let _ = stream.write_all(
|
|
2736
|
+
b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n",
|
|
2737
|
+
);
|
|
2542
2738
|
let _ = stream.shutdown(std::net::Shutdown::Write);
|
|
2543
2739
|
}
|
|
2544
2740
|
});
|
|
@@ -2603,7 +2799,11 @@ impl Evaluator {
|
|
|
2603
2799
|
tishlang_ast::DestructPattern::Array(elements) => {
|
|
2604
2800
|
let arr = match value {
|
|
2605
2801
|
Value::Array(a) => a.borrow().clone(),
|
|
2606
|
-
_ =>
|
|
2802
|
+
_ => {
|
|
2803
|
+
return Err(EvalError::Error(
|
|
2804
|
+
"Cannot destructure non-array value".to_string(),
|
|
2805
|
+
))
|
|
2806
|
+
}
|
|
2607
2807
|
};
|
|
2608
2808
|
|
|
2609
2809
|
for (i, elem) in elements.iter().enumerate() {
|
|
@@ -2633,7 +2833,11 @@ impl Evaluator {
|
|
|
2633
2833
|
tishlang_ast::DestructPattern::Object(props) => {
|
|
2634
2834
|
let obj = match value {
|
|
2635
2835
|
Value::Object(o) => o.borrow().clone(),
|
|
2636
|
-
_ =>
|
|
2836
|
+
_ => {
|
|
2837
|
+
return Err(EvalError::Error(
|
|
2838
|
+
"Cannot destructure non-object value".to_string(),
|
|
2839
|
+
))
|
|
2840
|
+
}
|
|
2637
2841
|
};
|
|
2638
2842
|
|
|
2639
2843
|
for prop in props {
|
|
@@ -2657,7 +2861,12 @@ impl Evaluator {
|
|
|
2657
2861
|
Ok(())
|
|
2658
2862
|
}
|
|
2659
2863
|
|
|
2660
|
-
fn bind_destruct_pattern(
|
|
2864
|
+
fn bind_destruct_pattern(
|
|
2865
|
+
&mut self,
|
|
2866
|
+
pattern: &tishlang_ast::DestructPattern,
|
|
2867
|
+
value: &Value,
|
|
2868
|
+
mutable: bool,
|
|
2869
|
+
) -> Result<(), EvalError> {
|
|
2661
2870
|
Self::bind_destruct_pattern_scoped(&self.scope, pattern, value, mutable)
|
|
2662
2871
|
}
|
|
2663
2872
|
|
|
@@ -2675,11 +2884,8 @@ impl Evaluator {
|
|
|
2675
2884
|
Some(Value::Bool(b)) => tishlang_core::Value::Bool(*b),
|
|
2676
2885
|
Some(_) => tishlang_core::Value::Number(0.0),
|
|
2677
2886
|
};
|
|
2678
|
-
let out =
|
|
2679
|
-
receiver.as_ref(),
|
|
2680
|
-
search,
|
|
2681
|
-
&position_core,
|
|
2682
|
-
);
|
|
2887
|
+
let out =
|
|
2888
|
+
tishlang_builtins::string::last_index_of_str(receiver.as_ref(), search, &position_core);
|
|
2683
2889
|
match out {
|
|
2684
2890
|
tishlang_core::Value::Number(n) => Value::Number(n),
|
|
2685
2891
|
_ => Value::Number(-1.0),
|
|
@@ -2963,7 +3169,9 @@ impl Evaluator {
|
|
|
2963
3169
|
Ok((Value::Bool(false), rest))
|
|
2964
3170
|
} else {
|
|
2965
3171
|
let end = s
|
|
2966
|
-
.find(|c: char|
|
|
3172
|
+
.find(|c: char| {
|
|
3173
|
+
!c.is_ascii_digit() && c != '-' && c != '+' && c != '.' && c != 'e' && c != 'E'
|
|
3174
|
+
})
|
|
2967
3175
|
.unwrap_or(s.len());
|
|
2968
3176
|
let num_str = &s[..end];
|
|
2969
3177
|
let n: f64 = num_str.parse().map_err(|_| ())?;
|
|
@@ -2991,7 +3199,11 @@ impl Evaluator {
|
|
|
2991
3199
|
.replace('\t', "\\t")
|
|
2992
3200
|
),
|
|
2993
3201
|
Value::Array(arr) => {
|
|
2994
|
-
let inner: Vec<String> = arr
|
|
3202
|
+
let inner: Vec<String> = arr
|
|
3203
|
+
.borrow()
|
|
3204
|
+
.iter()
|
|
3205
|
+
.map(Self::json_stringify_value)
|
|
3206
|
+
.collect();
|
|
2995
3207
|
format!("[{}]", inner.join(","))
|
|
2996
3208
|
}
|
|
2997
3209
|
Value::Object(map) => {
|
|
@@ -3010,7 +3222,14 @@ impl Evaluator {
|
|
|
3010
3222
|
})
|
|
3011
3223
|
.collect();
|
|
3012
3224
|
entries.sort_by(|a, b| a.0.cmp(&b.0));
|
|
3013
|
-
format!(
|
|
3225
|
+
format!(
|
|
3226
|
+
"{{{}}}",
|
|
3227
|
+
entries
|
|
3228
|
+
.into_iter()
|
|
3229
|
+
.map(|(_, s)| s)
|
|
3230
|
+
.collect::<Vec<_>>()
|
|
3231
|
+
.join(",")
|
|
3232
|
+
)
|
|
3014
3233
|
}
|
|
3015
3234
|
Value::Function { .. } | Value::Native(_) => "null".to_string(),
|
|
3016
3235
|
#[cfg(feature = "http")]
|
|
@@ -3021,7 +3240,8 @@ impl Evaluator {
|
|
|
3021
3240
|
| Value::Promise(_)
|
|
3022
3241
|
| Value::PromiseResolver(_)
|
|
3023
3242
|
| Value::PromiseConstructor
|
|
3024
|
-
| Value::BoundPromiseMethod(_, _)
|
|
3243
|
+
| Value::BoundPromiseMethod(_, _)
|
|
3244
|
+
| Value::TimerBuiltin(_) => "null".to_string(),
|
|
3025
3245
|
#[cfg(feature = "regex")]
|
|
3026
3246
|
Value::RegExp(_) => "null".to_string(),
|
|
3027
3247
|
Value::Opaque(_) | Value::OpaqueMethod(_, _) => "null".to_string(),
|
|
@@ -3041,7 +3261,11 @@ impl Evaluator {
|
|
|
3041
3261
|
|
|
3042
3262
|
fn object_keys(args: &[Value]) -> Result<Value, String> {
|
|
3043
3263
|
if let Some(Value::Object(obj)) = args.first() {
|
|
3044
|
-
let keys: Vec<Value> = obj
|
|
3264
|
+
let keys: Vec<Value> = obj
|
|
3265
|
+
.borrow()
|
|
3266
|
+
.keys()
|
|
3267
|
+
.map(|k| Value::String(Arc::clone(k)))
|
|
3268
|
+
.collect();
|
|
3045
3269
|
Ok(Value::Array(Rc::new(RefCell::new(keys))))
|
|
3046
3270
|
} else {
|
|
3047
3271
|
Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
|
|
@@ -3059,12 +3283,16 @@ impl Evaluator {
|
|
|
3059
3283
|
|
|
3060
3284
|
fn object_entries(args: &[Value]) -> Result<Value, String> {
|
|
3061
3285
|
if let Some(Value::Object(obj)) = args.first() {
|
|
3062
|
-
let entries: Vec<Value> = obj
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3286
|
+
let entries: Vec<Value> = obj
|
|
3287
|
+
.borrow()
|
|
3288
|
+
.iter()
|
|
3289
|
+
.map(|(k, v)| {
|
|
3290
|
+
Value::Array(Rc::new(RefCell::new(vec![
|
|
3291
|
+
Value::String(Arc::clone(k)),
|
|
3292
|
+
v.clone(),
|
|
3293
|
+
])))
|
|
3294
|
+
})
|
|
3295
|
+
.collect();
|
|
3068
3296
|
Ok(Value::Array(Rc::new(RefCell::new(entries))))
|
|
3069
3297
|
} else {
|
|
3070
3298
|
Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
|
|
@@ -3136,7 +3364,10 @@ impl Evaluator {
|
|
|
3136
3364
|
.ok_or_else(|| "Promise.all requires an iterable".to_string())?;
|
|
3137
3365
|
let values: Vec<Value> = match iterable {
|
|
3138
3366
|
Value::Array(arr) => arr.borrow().clone(),
|
|
3139
|
-
Value::String(s) => s
|
|
3367
|
+
Value::String(s) => s
|
|
3368
|
+
.chars()
|
|
3369
|
+
.map(|c| Value::String(c.to_string().into()))
|
|
3370
|
+
.collect(),
|
|
3140
3371
|
_ => return Err("Promise.all requires array or iterable".to_string()),
|
|
3141
3372
|
};
|
|
3142
3373
|
let mut results = Vec::with_capacity(values.len());
|
|
@@ -3146,7 +3377,8 @@ impl Evaluator {
|
|
|
3146
3377
|
crate::promise::PromiseAwaitResult::Fulfilled(x) => results.push(x),
|
|
3147
3378
|
crate::promise::PromiseAwaitResult::Rejected(x) => {
|
|
3148
3379
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3149
|
-
let (_, reject) =
|
|
3380
|
+
let (_, reject) =
|
|
3381
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3150
3382
|
let _ = crate::promise::settle_promise(&reject, x, false);
|
|
3151
3383
|
return Ok(promise);
|
|
3152
3384
|
}
|
|
@@ -3157,7 +3389,8 @@ impl Evaluator {
|
|
|
3157
3389
|
Ok(x) => results.push(crate::value_convert::core_to_eval(x)),
|
|
3158
3390
|
Err(x) => {
|
|
3159
3391
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3160
|
-
let (_, reject) =
|
|
3392
|
+
let (_, reject) =
|
|
3393
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3161
3394
|
let _ = crate::promise::settle_promise(
|
|
3162
3395
|
&reject,
|
|
3163
3396
|
crate::value_convert::core_to_eval(x),
|
|
@@ -3184,7 +3417,10 @@ impl Evaluator {
|
|
|
3184
3417
|
.ok_or_else(|| "Promise.race requires an iterable".to_string())?;
|
|
3185
3418
|
let values: Vec<Value> = match iterable {
|
|
3186
3419
|
Value::Array(arr) => arr.borrow().clone(),
|
|
3187
|
-
Value::String(s) => s
|
|
3420
|
+
Value::String(s) => s
|
|
3421
|
+
.chars()
|
|
3422
|
+
.map(|c| Value::String(c.to_string().into()))
|
|
3423
|
+
.collect(),
|
|
3188
3424
|
_ => return Err("Promise.race requires array or iterable".to_string()),
|
|
3189
3425
|
};
|
|
3190
3426
|
for v in values {
|
|
@@ -3192,7 +3428,8 @@ impl Evaluator {
|
|
|
3192
3428
|
match p.block_until_settled() {
|
|
3193
3429
|
Ok(x) => {
|
|
3194
3430
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3195
|
-
let (resolve, _) =
|
|
3431
|
+
let (resolve, _) =
|
|
3432
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3196
3433
|
crate::promise::settle_promise(
|
|
3197
3434
|
&resolve,
|
|
3198
3435
|
crate::value_convert::core_to_eval(x),
|
|
@@ -3202,7 +3439,8 @@ impl Evaluator {
|
|
|
3202
3439
|
}
|
|
3203
3440
|
Err(x) => {
|
|
3204
3441
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3205
|
-
let (_, reject) =
|
|
3442
|
+
let (_, reject) =
|
|
3443
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3206
3444
|
crate::promise::settle_promise(
|
|
3207
3445
|
&reject,
|
|
3208
3446
|
crate::value_convert::core_to_eval(x),
|
|
@@ -3216,13 +3454,15 @@ impl Evaluator {
|
|
|
3216
3454
|
match crate::promise::block_until_settled(p) {
|
|
3217
3455
|
crate::promise::PromiseAwaitResult::Fulfilled(x) => {
|
|
3218
3456
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3219
|
-
let (resolve, _) =
|
|
3457
|
+
let (resolve, _) =
|
|
3458
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3220
3459
|
crate::promise::settle_promise(&resolve, x, true)?;
|
|
3221
3460
|
return Ok(promise);
|
|
3222
3461
|
}
|
|
3223
3462
|
crate::promise::PromiseAwaitResult::Rejected(x) => {
|
|
3224
3463
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3225
|
-
let (_, reject) =
|
|
3464
|
+
let (_, reject) =
|
|
3465
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3226
3466
|
crate::promise::settle_promise(&reject, x, false)?;
|
|
3227
3467
|
return Ok(promise);
|
|
3228
3468
|
}
|
|
@@ -3239,7 +3479,9 @@ impl Evaluator {
|
|
|
3239
3479
|
for a in args {
|
|
3240
3480
|
cv.push(crate::value_convert::eval_to_core(a)?);
|
|
3241
3481
|
}
|
|
3242
|
-
Ok(crate::value_convert::core_to_eval(
|
|
3482
|
+
Ok(crate::value_convert::core_to_eval(
|
|
3483
|
+
tishlang_runtime::web_socket_client(&cv),
|
|
3484
|
+
))
|
|
3243
3485
|
}
|
|
3244
3486
|
|
|
3245
3487
|
#[cfg(feature = "ws")]
|
|
@@ -3248,7 +3490,9 @@ impl Evaluator {
|
|
|
3248
3490
|
for a in args {
|
|
3249
3491
|
cv.push(crate::value_convert::eval_to_core(a)?);
|
|
3250
3492
|
}
|
|
3251
|
-
Ok(crate::value_convert::core_to_eval(
|
|
3493
|
+
Ok(crate::value_convert::core_to_eval(
|
|
3494
|
+
tishlang_runtime::web_socket_server_construct(&cv),
|
|
3495
|
+
))
|
|
3252
3496
|
}
|
|
3253
3497
|
|
|
3254
3498
|
#[cfg(feature = "ws")]
|
|
@@ -3256,7 +3500,9 @@ impl Evaluator {
|
|
|
3256
3500
|
let conn = args.first().ok_or("wsSend(conn, data) requires conn")?;
|
|
3257
3501
|
let conn_core = crate::value_convert::eval_to_core(conn)?;
|
|
3258
3502
|
let data = args.get(1).map(|v| v.to_string()).unwrap_or_default();
|
|
3259
|
-
Ok(Value::Bool(tishlang_runtime::ws_send_native(
|
|
3503
|
+
Ok(Value::Bool(tishlang_runtime::ws_send_native(
|
|
3504
|
+
&conn_core, &data,
|
|
3505
|
+
)))
|
|
3260
3506
|
}
|
|
3261
3507
|
|
|
3262
3508
|
#[cfg(feature = "ws")]
|
|
@@ -3265,7 +3511,9 @@ impl Evaluator {
|
|
|
3265
3511
|
for a in args {
|
|
3266
3512
|
cv.push(crate::value_convert::eval_to_core(a)?);
|
|
3267
3513
|
}
|
|
3268
|
-
Ok(crate::value_convert::core_to_eval(
|
|
3514
|
+
Ok(crate::value_convert::core_to_eval(
|
|
3515
|
+
tishlang_runtime::ws_broadcast_native(&cv),
|
|
3516
|
+
))
|
|
3269
3517
|
}
|
|
3270
3518
|
|
|
3271
3519
|
#[cfg(feature = "http")]
|
|
@@ -3319,7 +3567,6 @@ impl Evaluator {
|
|
|
3319
3567
|
"await requires the http feature".to_string(),
|
|
3320
3568
|
))
|
|
3321
3569
|
}
|
|
3322
|
-
|
|
3323
3570
|
}
|
|
3324
3571
|
|
|
3325
3572
|
#[derive(Debug)]
|