@tishlang/tish 1.6.0 → 1.8.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/error.rs +2 -8
- package/crates/js_to_tish/src/transform/expr.rs +128 -137
- package/crates/js_to_tish/src/transform/stmt.rs +62 -32
- package/crates/tish/Cargo.toml +15 -5
- package/crates/tish/src/cargo_native_registry.rs +29 -0
- package/crates/tish/src/cli_help.rs +92 -39
- package/crates/tish/src/main.rs +172 -86
- package/crates/tish/src/repl_completion.rs +3 -3
- package/crates/tish/tests/cargo_example_compile.rs +4 -2
- package/crates/tish/tests/integration_test.rs +216 -54
- package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
- package/crates/tish/tests/shortcircuit.rs +20 -5
- package/crates/tish_ast/src/ast.rs +92 -23
- package/crates/tish_build_utils/Cargo.toml +4 -0
- package/crates/tish_build_utils/src/lib.rs +136 -8
- package/crates/tish_builtins/Cargo.toml +5 -1
- package/crates/tish_builtins/src/array.rs +65 -33
- package/crates/tish_builtins/src/construct.rs +34 -39
- package/crates/tish_builtins/src/globals.rs +42 -26
- package/crates/tish_builtins/src/helpers.rs +2 -1
- package/crates/tish_builtins/src/lib.rs +5 -5
- package/crates/tish_builtins/src/math.rs +5 -3
- package/crates/tish_builtins/src/object.rs +3 -2
- package/crates/tish_builtins/src/string.rs +144 -22
- package/crates/tish_bytecode/src/chunk.rs +0 -1
- package/crates/tish_bytecode/src/compiler.rs +173 -71
- package/crates/tish_bytecode/src/opcode.rs +24 -6
- package/crates/tish_bytecode/src/peephole.rs +2 -2
- package/crates/tish_compile/Cargo.toml +1 -0
- package/crates/tish_compile/src/codegen.rs +1621 -453
- package/crates/tish_compile/src/infer.rs +75 -19
- package/crates/tish_compile/src/lib.rs +19 -8
- package/crates/tish_compile/src/resolve.rs +278 -137
- package/crates/tish_compile/src/types.rs +184 -24
- package/crates/tish_compile_js/Cargo.toml +1 -0
- package/crates/tish_compile_js/src/codegen.rs +181 -37
- package/crates/tish_compile_js/src/lib.rs +3 -1
- 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 +69 -59
- package/crates/tish_core/Cargo.toml +8 -0
- package/crates/tish_core/src/json.rs +107 -56
- package/crates/tish_core/src/lib.rs +4 -2
- package/crates/tish_core/src/macros.rs +5 -5
- package/crates/tish_core/src/uri.rs +9 -6
- package/crates/tish_core/src/value.rs +145 -43
- package/crates/tish_core/src/vmref.rs +178 -0
- package/crates/tish_cranelift/src/link.rs +6 -9
- package/crates/tish_cranelift/src/lower.rs +14 -8
- package/crates/tish_eval/Cargo.toml +17 -2
- package/crates/tish_eval/src/eval.rs +474 -165
- package/crates/tish_eval/src/http.rs +61 -0
- package/crates/tish_eval/src/lib.rs +12 -8
- package/crates/tish_eval/src/natives.rs +136 -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 +17 -6
- package/crates/tish_eval/src/value_convert.rs +13 -5
- package/crates/tish_fmt/src/lib.rs +149 -43
- package/crates/tish_lexer/src/lib.rs +232 -63
- package/crates/tish_lexer/src/token.rs +10 -6
- package/crates/tish_llvm/src/lib.rs +17 -8
- 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 +504 -106
- package/crates/tish_native/src/build.rs +4 -8
- package/crates/tish_native/src/lib.rs +54 -21
- package/crates/tish_opt/src/lib.rs +84 -52
- package/crates/tish_parser/src/lib.rs +45 -13
- package/crates/tish_parser/src/parser.rs +505 -130
- 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 +1136 -145
- package/crates/tish_runtime/src/http_fetch.rs +38 -27
- 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 +375 -189
- package/crates/tish_runtime/src/promise.rs +199 -40
- 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 +65 -42
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
- package/crates/tish_ui/src/jsx.rs +317 -27
- 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 +725 -281
- package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +11 -4
- package/crates/tish_wasm/src/lib.rs +55 -42
- 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 +26 -0
- package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
- package/crates/tishlang_cargo_bindgen/src/discover.rs +120 -0
- package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
- package/crates/tishlang_cargo_bindgen/src/lib.rs +350 -0
- package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -0
- 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
|
@@ -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,25 @@ 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("htmlEscape".into(), Value::Native(natives::html_escape), true);
|
|
113
|
+
s.set(
|
|
114
|
+
"Boolean".into(),
|
|
115
|
+
Value::Native(natives::boolean_native),
|
|
116
|
+
true,
|
|
117
|
+
);
|
|
102
118
|
s.set("isFinite".into(), Value::Native(natives::is_finite), true);
|
|
103
119
|
s.set("isNaN".into(), Value::Native(natives::is_nan), true);
|
|
104
120
|
s.set("Infinity".into(), Value::Number(f64::INFINITY), true);
|
|
@@ -122,32 +138,65 @@ impl Evaluator {
|
|
|
122
138
|
math.insert("trunc".into(), Value::Native(natives::math_trunc));
|
|
123
139
|
math.insert("PI".into(), Value::Number(std::f64::consts::PI));
|
|
124
140
|
math.insert("E".into(), Value::Number(std::f64::consts::E));
|
|
125
|
-
s.set(
|
|
141
|
+
s.set(
|
|
142
|
+
"Math".into(),
|
|
143
|
+
Value::Object(Rc::new(RefCell::new(math))),
|
|
144
|
+
true,
|
|
145
|
+
);
|
|
126
146
|
|
|
127
147
|
let mut json = PropMap::with_capacity(2);
|
|
128
148
|
json.insert("parse".into(), Value::Native(Self::json_parse_native));
|
|
129
|
-
json.insert(
|
|
130
|
-
|
|
149
|
+
json.insert(
|
|
150
|
+
"stringify".into(),
|
|
151
|
+
Value::Native(Self::json_stringify_native),
|
|
152
|
+
);
|
|
153
|
+
s.set(
|
|
154
|
+
"JSON".into(),
|
|
155
|
+
Value::Object(Rc::new(RefCell::new(json))),
|
|
156
|
+
true,
|
|
157
|
+
);
|
|
131
158
|
|
|
132
159
|
let mut object = PropMap::with_capacity(5);
|
|
133
160
|
object.insert("keys".into(), Value::Native(Self::object_keys));
|
|
134
161
|
object.insert("values".into(), Value::Native(Self::object_values));
|
|
135
162
|
object.insert("entries".into(), Value::Native(Self::object_entries));
|
|
136
163
|
object.insert("assign".into(), Value::Native(Self::object_assign));
|
|
137
|
-
object.insert(
|
|
138
|
-
|
|
164
|
+
object.insert(
|
|
165
|
+
"fromEntries".into(),
|
|
166
|
+
Value::Native(Self::object_from_entries),
|
|
167
|
+
);
|
|
168
|
+
s.set(
|
|
169
|
+
"Object".into(),
|
|
170
|
+
Value::Object(Rc::new(RefCell::new(object))),
|
|
171
|
+
true,
|
|
172
|
+
);
|
|
139
173
|
|
|
140
174
|
let mut array_obj = PropMap::with_capacity(1);
|
|
141
175
|
array_obj.insert("isArray".into(), Value::Native(natives::array_is_array));
|
|
142
|
-
s.set(
|
|
176
|
+
s.set(
|
|
177
|
+
"Array".into(),
|
|
178
|
+
Value::Object(Rc::new(RefCell::new(array_obj))),
|
|
179
|
+
true,
|
|
180
|
+
);
|
|
143
181
|
|
|
144
182
|
let mut string_obj = PropMap::with_capacity(1);
|
|
145
|
-
string_obj.insert(
|
|
146
|
-
|
|
183
|
+
string_obj.insert(
|
|
184
|
+
"fromCharCode".into(),
|
|
185
|
+
Value::Native(natives::string_from_char_code),
|
|
186
|
+
);
|
|
187
|
+
s.set(
|
|
188
|
+
"String".into(),
|
|
189
|
+
Value::Object(Rc::new(RefCell::new(string_obj))),
|
|
190
|
+
true,
|
|
191
|
+
);
|
|
147
192
|
|
|
148
193
|
let mut date = PropMap::with_capacity(1);
|
|
149
194
|
date.insert("now".into(), Value::Native(natives::date_now));
|
|
150
|
-
s.set(
|
|
195
|
+
s.set(
|
|
196
|
+
"Date".into(),
|
|
197
|
+
Value::Object(Rc::new(RefCell::new(date))),
|
|
198
|
+
true,
|
|
199
|
+
);
|
|
151
200
|
|
|
152
201
|
s.set(
|
|
153
202
|
"Uint8Array".into(),
|
|
@@ -166,10 +215,44 @@ impl Evaluator {
|
|
|
166
215
|
|
|
167
216
|
#[cfg(feature = "regex")]
|
|
168
217
|
{
|
|
169
|
-
s.set(
|
|
218
|
+
s.set(
|
|
219
|
+
"RegExp".into(),
|
|
220
|
+
Value::Native(Self::regexp_constructor_native),
|
|
221
|
+
true,
|
|
222
|
+
);
|
|
170
223
|
}
|
|
171
224
|
|
|
172
|
-
// fs,
|
|
225
|
+
// fs, process: prefer `import { x } from 'tish:fs'` etc.
|
|
226
|
+
#[cfg(feature = "timers")]
|
|
227
|
+
{
|
|
228
|
+
s.set(
|
|
229
|
+
"setTimeout".into(),
|
|
230
|
+
Value::TimerBuiltin(Arc::from("setTimeout")),
|
|
231
|
+
true,
|
|
232
|
+
);
|
|
233
|
+
s.set(
|
|
234
|
+
"setInterval".into(),
|
|
235
|
+
Value::TimerBuiltin(Arc::from("setInterval")),
|
|
236
|
+
true,
|
|
237
|
+
);
|
|
238
|
+
s.set(
|
|
239
|
+
"clearTimeout".into(),
|
|
240
|
+
Value::Native(Self::clear_timeout_native),
|
|
241
|
+
true,
|
|
242
|
+
);
|
|
243
|
+
s.set(
|
|
244
|
+
"clearInterval".into(),
|
|
245
|
+
Value::Native(Self::clear_interval_native),
|
|
246
|
+
true,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
#[cfg(feature = "http")]
|
|
250
|
+
{
|
|
251
|
+
s.set("fetch".into(), Value::Native(Self::fetch_native), true);
|
|
252
|
+
s.set("fetchAll".into(), Value::Native(Self::fetch_all_native), true);
|
|
253
|
+
s.set("Promise".into(), Value::PromiseConstructor, true);
|
|
254
|
+
s.set("serve".into(), Value::Serve, true);
|
|
255
|
+
}
|
|
173
256
|
}
|
|
174
257
|
Self {
|
|
175
258
|
scope,
|
|
@@ -225,16 +308,28 @@ impl Evaluator {
|
|
|
225
308
|
self.scope = prev;
|
|
226
309
|
Ok(last)
|
|
227
310
|
}
|
|
228
|
-
Statement::VarDecl {
|
|
311
|
+
Statement::VarDecl {
|
|
312
|
+
name,
|
|
313
|
+
mutable,
|
|
314
|
+
init,
|
|
315
|
+
..
|
|
316
|
+
} => {
|
|
229
317
|
let value = init
|
|
230
318
|
.as_ref()
|
|
231
319
|
.map(|e| self.eval_expr(e))
|
|
232
320
|
.transpose()?
|
|
233
321
|
.unwrap_or(Value::Null);
|
|
234
|
-
self.scope
|
|
322
|
+
self.scope
|
|
323
|
+
.borrow_mut()
|
|
324
|
+
.set(Arc::clone(name), value, *mutable);
|
|
235
325
|
Ok(Value::Null)
|
|
236
326
|
}
|
|
237
|
-
Statement::VarDeclDestructure {
|
|
327
|
+
Statement::VarDeclDestructure {
|
|
328
|
+
pattern,
|
|
329
|
+
mutable,
|
|
330
|
+
init,
|
|
331
|
+
..
|
|
332
|
+
} => {
|
|
238
333
|
let value = self.eval_expr(init)?;
|
|
239
334
|
self.bind_destruct_pattern(pattern, &value, *mutable)?;
|
|
240
335
|
Ok(Value::Null)
|
|
@@ -269,15 +364,21 @@ impl Evaluator {
|
|
|
269
364
|
}
|
|
270
365
|
Ok(Value::Null)
|
|
271
366
|
}
|
|
272
|
-
Statement::ForOf {
|
|
367
|
+
Statement::ForOf {
|
|
368
|
+
name,
|
|
369
|
+
iterable,
|
|
370
|
+
body,
|
|
371
|
+
..
|
|
372
|
+
} => {
|
|
273
373
|
let iter_val = self.eval_expr(iterable)?;
|
|
274
374
|
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<_>>()
|
|
375
|
+
crate::value::Value::Array(arr) => {
|
|
376
|
+
arr.borrow().iter().cloned().collect::<Vec<_>>()
|
|
280
377
|
}
|
|
378
|
+
crate::value::Value::String(s) => s
|
|
379
|
+
.chars()
|
|
380
|
+
.map(|c| crate::value::Value::String(Arc::from(c.to_string())))
|
|
381
|
+
.collect::<Vec<_>>(),
|
|
281
382
|
_ => {
|
|
282
383
|
return Err(EvalError::Error(format!(
|
|
283
384
|
"for-of requires iterable (array or string), got {}",
|
|
@@ -360,7 +461,12 @@ impl Evaluator {
|
|
|
360
461
|
self.scope.borrow_mut().set(Arc::clone(name), func, true);
|
|
361
462
|
Ok(Value::Null)
|
|
362
463
|
}
|
|
363
|
-
Statement::Switch {
|
|
464
|
+
Statement::Switch {
|
|
465
|
+
expr,
|
|
466
|
+
cases,
|
|
467
|
+
default_body,
|
|
468
|
+
..
|
|
469
|
+
} => {
|
|
364
470
|
let v = self.eval_expr(expr)?;
|
|
365
471
|
let mut matched = false;
|
|
366
472
|
for (case_expr, body) in cases {
|
|
@@ -438,7 +544,7 @@ impl Evaluator {
|
|
|
438
544
|
..
|
|
439
545
|
} => {
|
|
440
546
|
let try_result = self.eval_statement(body);
|
|
441
|
-
|
|
547
|
+
|
|
442
548
|
let result = match try_result {
|
|
443
549
|
Ok(v) => Ok(v),
|
|
444
550
|
Err(EvalError::Throw(thrown)) => {
|
|
@@ -459,37 +565,43 @@ impl Evaluator {
|
|
|
459
565
|
}
|
|
460
566
|
Err(e) => Err(e),
|
|
461
567
|
};
|
|
462
|
-
|
|
568
|
+
|
|
463
569
|
if let Some(finally_stmt) = finally_body {
|
|
464
570
|
let _ = self.eval_statement(finally_stmt);
|
|
465
571
|
}
|
|
466
|
-
|
|
572
|
+
|
|
467
573
|
result
|
|
468
574
|
}
|
|
469
|
-
Statement::Import {
|
|
575
|
+
Statement::Import {
|
|
576
|
+
specifiers, from, ..
|
|
577
|
+
} => {
|
|
470
578
|
let exports_val = self.load_module(from)?;
|
|
471
579
|
let exports = match &exports_val {
|
|
472
580
|
Value::Object(m) => m.borrow().clone(),
|
|
473
|
-
_ =>
|
|
581
|
+
_ => {
|
|
582
|
+
return Err(EvalError::Error(
|
|
583
|
+
"Module exports must be object".to_string(),
|
|
584
|
+
))
|
|
585
|
+
}
|
|
474
586
|
};
|
|
475
587
|
let mut scope = self.scope.borrow_mut();
|
|
476
588
|
for spec in specifiers {
|
|
477
589
|
match spec {
|
|
478
|
-
ImportSpecifier::Named { name, alias } => {
|
|
590
|
+
ImportSpecifier::Named { name, alias, .. } => {
|
|
479
591
|
let v = exports.get(name.as_ref()).ok_or_else(|| {
|
|
480
592
|
EvalError::Error(format!("Module does not export '{}'", name))
|
|
481
593
|
})?;
|
|
482
594
|
let bind = alias.as_deref().unwrap_or(name.as_ref());
|
|
483
595
|
scope.set(Arc::from(bind), v.clone(), false);
|
|
484
596
|
}
|
|
485
|
-
ImportSpecifier::Namespace
|
|
486
|
-
scope.set(Arc::clone(
|
|
597
|
+
ImportSpecifier::Namespace { name, .. } => {
|
|
598
|
+
scope.set(Arc::clone(name), exports_val.clone(), false);
|
|
487
599
|
}
|
|
488
|
-
ImportSpecifier::Default
|
|
600
|
+
ImportSpecifier::Default { name, .. } => {
|
|
489
601
|
let v = exports.get("default").ok_or_else(|| {
|
|
490
602
|
EvalError::Error("Module does not have default export".to_string())
|
|
491
603
|
})?;
|
|
492
|
-
scope.set(Arc::clone(
|
|
604
|
+
scope.set(Arc::clone(name), v.clone(), false);
|
|
493
605
|
}
|
|
494
606
|
}
|
|
495
607
|
}
|
|
@@ -507,6 +619,9 @@ impl Evaluator {
|
|
|
507
619
|
}
|
|
508
620
|
Ok(Value::Null)
|
|
509
621
|
}
|
|
622
|
+
Statement::TypeAlias { .. } | Statement::DeclareVar { .. } | Statement::DeclareFun { .. } => {
|
|
623
|
+
Ok(Value::Null)
|
|
624
|
+
}
|
|
510
625
|
}
|
|
511
626
|
}
|
|
512
627
|
|
|
@@ -514,7 +629,8 @@ impl Evaluator {
|
|
|
514
629
|
fn load_module(&mut self, from: &str) -> Result<Value, EvalError> {
|
|
515
630
|
if from.starts_with("cargo:") {
|
|
516
631
|
return Err(EvalError::Error(
|
|
517
|
-
"cargo:… imports are only supported by `tish build` with the Rust native backend."
|
|
632
|
+
"cargo:… imports are only supported by `tish build` with the Rust native backend."
|
|
633
|
+
.into(),
|
|
518
634
|
));
|
|
519
635
|
}
|
|
520
636
|
if from.starts_with("tish:") {
|
|
@@ -525,24 +641,24 @@ impl Evaluator {
|
|
|
525
641
|
return self.load_builtin_module(from);
|
|
526
642
|
}
|
|
527
643
|
let dir = self.current_dir.borrow().clone().ok_or_else(|| {
|
|
528
|
-
EvalError::Error(
|
|
644
|
+
EvalError::Error(
|
|
645
|
+
"Cannot resolve imports: no current file directory (use run_file)".to_string(),
|
|
646
|
+
)
|
|
529
647
|
})?;
|
|
530
648
|
let path = Self::resolve_import_path(from, &dir)?;
|
|
531
|
-
let path = path
|
|
532
|
-
|
|
533
|
-
|
|
649
|
+
let path = path
|
|
650
|
+
.canonicalize()
|
|
651
|
+
.map_err(|e| EvalError::Error(format!("Cannot resolve import '{}': {}", from, e)))?;
|
|
534
652
|
{
|
|
535
653
|
let cache = self.module_cache.borrow();
|
|
536
654
|
if let Some(m) = cache.get(&path) {
|
|
537
655
|
return Ok(m.clone());
|
|
538
656
|
}
|
|
539
657
|
}
|
|
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
|
-
})?;
|
|
658
|
+
let source = std::fs::read_to_string(&path)
|
|
659
|
+
.map_err(|e| EvalError::Error(format!("Cannot read {}: {}", path.display(), e)))?;
|
|
660
|
+
let program = tishlang_parser::parse(&source)
|
|
661
|
+
.map_err(|e| EvalError::Error(format!("Parse error in {}: {}", path.display(), e)))?;
|
|
546
662
|
let module_scope = Scope::child(Rc::clone(&self.scope));
|
|
547
663
|
let prev_scope = std::mem::replace(&mut self.scope, Rc::clone(&module_scope));
|
|
548
664
|
let parent_dir = self.current_dir.borrow().clone();
|
|
@@ -554,7 +670,9 @@ impl Evaluator {
|
|
|
554
670
|
match declaration.as_ref() {
|
|
555
671
|
ExportDeclaration::Named(s) => {
|
|
556
672
|
let _ = self.eval_statement(s);
|
|
557
|
-
if let Statement::VarDecl { name, .. } | Statement::FunDecl { name, .. } =
|
|
673
|
+
if let Statement::VarDecl { name, .. } | Statement::FunDecl { name, .. } =
|
|
674
|
+
s.as_ref()
|
|
675
|
+
{
|
|
558
676
|
export_names.push(name.to_string());
|
|
559
677
|
}
|
|
560
678
|
}
|
|
@@ -577,7 +695,9 @@ impl Evaluator {
|
|
|
577
695
|
*self.current_dir.borrow_mut() = parent_dir;
|
|
578
696
|
self.scope = prev_scope;
|
|
579
697
|
let exports_val = Value::Object(Rc::new(RefCell::new(exports)));
|
|
580
|
-
self.module_cache
|
|
698
|
+
self.module_cache
|
|
699
|
+
.borrow_mut()
|
|
700
|
+
.insert(path, exports_val.clone());
|
|
581
701
|
Ok(exports_val)
|
|
582
702
|
}
|
|
583
703
|
|
|
@@ -640,10 +760,6 @@ impl Evaluator {
|
|
|
640
760
|
exports.insert("fetchAll".into(), Value::Native(Self::fetch_all_native));
|
|
641
761
|
exports.insert("serve".into(), Value::Serve);
|
|
642
762
|
exports.insert("Promise".into(), Value::PromiseConstructor);
|
|
643
|
-
exports.insert("setTimeout".into(), Value::TimerBuiltin(Arc::from("setTimeout")));
|
|
644
|
-
exports.insert("setInterval".into(), Value::TimerBuiltin(Arc::from("setInterval")));
|
|
645
|
-
exports.insert("clearTimeout".into(), Value::Native(Self::clear_timeout_native));
|
|
646
|
-
exports.insert("clearInterval".into(), Value::Native(Self::clear_interval_native));
|
|
647
763
|
return Ok(Value::Object(Rc::new(RefCell::new(exports))));
|
|
648
764
|
}
|
|
649
765
|
#[cfg(not(feature = "http"))]
|
|
@@ -653,14 +769,49 @@ impl Evaluator {
|
|
|
653
769
|
));
|
|
654
770
|
}
|
|
655
771
|
}
|
|
772
|
+
"tish:timers" => {
|
|
773
|
+
#[cfg(feature = "timers")]
|
|
774
|
+
{
|
|
775
|
+
let mut exports: PropMap = PropMap::default();
|
|
776
|
+
exports.insert(
|
|
777
|
+
"setTimeout".into(),
|
|
778
|
+
Value::TimerBuiltin(Arc::from("setTimeout")),
|
|
779
|
+
);
|
|
780
|
+
exports.insert(
|
|
781
|
+
"setInterval".into(),
|
|
782
|
+
Value::TimerBuiltin(Arc::from("setInterval")),
|
|
783
|
+
);
|
|
784
|
+
exports.insert(
|
|
785
|
+
"clearTimeout".into(),
|
|
786
|
+
Value::Native(Self::clear_timeout_native),
|
|
787
|
+
);
|
|
788
|
+
exports.insert(
|
|
789
|
+
"clearInterval".into(),
|
|
790
|
+
Value::Native(Self::clear_interval_native),
|
|
791
|
+
);
|
|
792
|
+
return Ok(Value::Object(Rc::new(RefCell::new(exports))));
|
|
793
|
+
}
|
|
794
|
+
#[cfg(not(feature = "timers"))]
|
|
795
|
+
{
|
|
796
|
+
return Err(EvalError::Error(
|
|
797
|
+
"tish:timers requires the timers feature. Rebuild with: cargo build -p tishlang --features timers".into(),
|
|
798
|
+
));
|
|
799
|
+
}
|
|
800
|
+
}
|
|
656
801
|
"tish:ws" => {
|
|
657
802
|
#[cfg(feature = "ws")]
|
|
658
803
|
{
|
|
659
804
|
let mut exports: PropMap = PropMap::default();
|
|
660
|
-
exports.insert(
|
|
805
|
+
exports.insert(
|
|
806
|
+
"WebSocket".into(),
|
|
807
|
+
Value::Native(Self::ws_web_socket_native),
|
|
808
|
+
);
|
|
661
809
|
exports.insert("Server".into(), Value::Native(Self::ws_server_native));
|
|
662
810
|
exports.insert("wsSend".into(), Value::Native(Self::ws_send_native));
|
|
663
|
-
exports.insert(
|
|
811
|
+
exports.insert(
|
|
812
|
+
"wsBroadcast".into(),
|
|
813
|
+
Value::Native(Self::ws_broadcast_native),
|
|
814
|
+
);
|
|
664
815
|
return Ok(Value::Object(Rc::new(RefCell::new(exports))));
|
|
665
816
|
}
|
|
666
817
|
#[cfg(not(feature = "ws"))]
|
|
@@ -677,21 +828,29 @@ impl Evaluator {
|
|
|
677
828
|
exports.insert("exit".into(), Value::Native(natives::process_exit));
|
|
678
829
|
exports.insert("cwd".into(), Value::Native(natives::process_cwd));
|
|
679
830
|
exports.insert("exec".into(), Value::Native(natives::process_exec));
|
|
680
|
-
let argv: Vec<Value> =
|
|
681
|
-
.map(|s| Value::String(s.into()))
|
|
682
|
-
|
|
683
|
-
|
|
831
|
+
let argv: Vec<Value> =
|
|
832
|
+
std::env::args().map(|s| Value::String(s.into())).collect();
|
|
833
|
+
exports.insert(
|
|
834
|
+
"argv".into(),
|
|
835
|
+
Value::Array(Rc::new(RefCell::new(argv.clone()))),
|
|
836
|
+
);
|
|
684
837
|
let env_obj: PropMap = std::env::vars()
|
|
685
838
|
.map(|(key, value)| (Arc::from(key.as_str()), Value::String(value.into())))
|
|
686
839
|
.collect();
|
|
687
|
-
exports.insert(
|
|
840
|
+
exports.insert(
|
|
841
|
+
"env".into(),
|
|
842
|
+
Value::Object(Rc::new(RefCell::new(env_obj.clone()))),
|
|
843
|
+
);
|
|
688
844
|
let mut process_obj = PropMap::default();
|
|
689
845
|
process_obj.insert("exit".into(), Value::Native(natives::process_exit));
|
|
690
846
|
process_obj.insert("cwd".into(), Value::Native(natives::process_cwd));
|
|
691
847
|
process_obj.insert("exec".into(), Value::Native(natives::process_exec));
|
|
692
848
|
process_obj.insert("argv".into(), Value::Array(Rc::new(RefCell::new(argv))));
|
|
693
849
|
process_obj.insert("env".into(), Value::Object(Rc::new(RefCell::new(env_obj))));
|
|
694
|
-
exports.insert(
|
|
850
|
+
exports.insert(
|
|
851
|
+
"process".into(),
|
|
852
|
+
Value::Object(Rc::new(RefCell::new(process_obj))),
|
|
853
|
+
);
|
|
695
854
|
return Ok(Value::Object(Rc::new(RefCell::new(exports))));
|
|
696
855
|
}
|
|
697
856
|
#[cfg(not(feature = "process"))]
|
|
@@ -703,7 +862,7 @@ impl Evaluator {
|
|
|
703
862
|
}
|
|
704
863
|
_ => {
|
|
705
864
|
return Err(EvalError::Error(format!(
|
|
706
|
-
"Unknown built-in module: {}. Supported: tish:fs, tish:http, tish:process, tish:ws (plus any registered by native modules)",
|
|
865
|
+
"Unknown built-in module: {}. Supported: tish:fs, tish:http, tish:timers, tish:process, tish:ws (plus any registered by native modules)",
|
|
707
866
|
spec
|
|
708
867
|
)));
|
|
709
868
|
}
|
|
@@ -750,7 +909,12 @@ impl Evaluator {
|
|
|
750
909
|
}
|
|
751
910
|
Expr::Call { callee, args, .. } => {
|
|
752
911
|
// Check for built-in method calls on arrays/strings
|
|
753
|
-
if let Expr::Member {
|
|
912
|
+
if let Expr::Member {
|
|
913
|
+
object,
|
|
914
|
+
prop: MemberProp::Name { name: method_name, .. },
|
|
915
|
+
..
|
|
916
|
+
} = callee.as_ref()
|
|
917
|
+
{
|
|
754
918
|
let obj = self.eval_expr(object)?;
|
|
755
919
|
let arg_vals = self.eval_call_args(args)?;
|
|
756
920
|
|
|
@@ -1517,7 +1681,7 @@ impl Evaluator {
|
|
|
1517
1681
|
return Ok(Value::Null);
|
|
1518
1682
|
}
|
|
1519
1683
|
let key = match prop {
|
|
1520
|
-
MemberProp::Name
|
|
1684
|
+
MemberProp::Name { name, .. } => Arc::clone(name),
|
|
1521
1685
|
MemberProp::Expr(e) => {
|
|
1522
1686
|
let v = self.eval_expr(e)?;
|
|
1523
1687
|
match v {
|
|
@@ -1638,7 +1802,9 @@ impl Evaluator {
|
|
|
1638
1802
|
Value::Serve
|
|
1639
1803
|
| Value::PromiseResolver(_)
|
|
1640
1804
|
| Value::PromiseConstructor
|
|
1641
|
-
| Value::BoundPromiseMethod(_, _)
|
|
1805
|
+
| Value::BoundPromiseMethod(_, _) => "function".into(),
|
|
1806
|
+
#[cfg(feature = "timers")]
|
|
1807
|
+
Value::TimerBuiltin(_) => "function".into(),
|
|
1642
1808
|
#[cfg(feature = "http")]
|
|
1643
1809
|
Value::Promise(_) => "object".into(),
|
|
1644
1810
|
#[cfg(feature = "regex")]
|
|
@@ -1912,7 +2078,13 @@ impl Evaluator {
|
|
|
1912
2078
|
/// descending = false: checks for `(a, b) => a - b`
|
|
1913
2079
|
/// descending = true: checks for `(a, b) => b - a`
|
|
1914
2080
|
fn is_numeric_sort_comparator(f: &Value, descending: bool) -> bool {
|
|
1915
|
-
if let Value::Function {
|
|
2081
|
+
if let Value::Function {
|
|
2082
|
+
formals,
|
|
2083
|
+
body,
|
|
2084
|
+
rest_param,
|
|
2085
|
+
..
|
|
2086
|
+
} = f
|
|
2087
|
+
{
|
|
1916
2088
|
// Must have exactly 2 simple params, no defaults, no rest
|
|
1917
2089
|
if formals.len() != 2 || rest_param.is_some() {
|
|
1918
2090
|
return false;
|
|
@@ -1936,15 +2108,29 @@ impl Evaluator {
|
|
|
1936
2108
|
};
|
|
1937
2109
|
|
|
1938
2110
|
// Check for binary subtraction
|
|
1939
|
-
if let Expr::Binary {
|
|
2111
|
+
if let Expr::Binary {
|
|
2112
|
+
left,
|
|
2113
|
+
op: BinOp::Sub,
|
|
2114
|
+
right,
|
|
2115
|
+
..
|
|
2116
|
+
} = expr
|
|
2117
|
+
{
|
|
1940
2118
|
// Check left is Ident(a) and right is Ident(b)
|
|
1941
2119
|
let (expected_left, expected_right) = if descending {
|
|
1942
|
-
(param_b, param_a)
|
|
2120
|
+
(param_b, param_a) // b - a
|
|
1943
2121
|
} else {
|
|
1944
|
-
(param_a, param_b)
|
|
2122
|
+
(param_a, param_b) // a - b
|
|
1945
2123
|
};
|
|
1946
2124
|
|
|
1947
|
-
if let (
|
|
2125
|
+
if let (
|
|
2126
|
+
Expr::Ident {
|
|
2127
|
+
name: left_name, ..
|
|
2128
|
+
},
|
|
2129
|
+
Expr::Ident {
|
|
2130
|
+
name: right_name, ..
|
|
2131
|
+
},
|
|
2132
|
+
) = (left.as_ref(), right.as_ref())
|
|
2133
|
+
{
|
|
1948
2134
|
return left_name == expected_left && right_name == expected_right;
|
|
1949
2135
|
}
|
|
1950
2136
|
}
|
|
@@ -1999,8 +2185,17 @@ impl Evaluator {
|
|
|
1999
2185
|
|
|
2000
2186
|
/// Optimized callback invocation for array methods.
|
|
2001
2187
|
/// Creates a reusable scope that can be updated for each iteration.
|
|
2002
|
-
fn create_callback_scope(
|
|
2003
|
-
|
|
2188
|
+
fn create_callback_scope(
|
|
2189
|
+
&self,
|
|
2190
|
+
f: &Value,
|
|
2191
|
+
) -> Option<(Rc<RefCell<Scope>>, Arc<[Arc<str>]>, Arc<Statement>)> {
|
|
2192
|
+
if let Value::Function {
|
|
2193
|
+
formals,
|
|
2194
|
+
body,
|
|
2195
|
+
rest_param,
|
|
2196
|
+
..
|
|
2197
|
+
} = f
|
|
2198
|
+
{
|
|
2004
2199
|
if rest_param.is_some() {
|
|
2005
2200
|
return None;
|
|
2006
2201
|
}
|
|
@@ -2063,12 +2258,14 @@ impl Evaluator {
|
|
|
2063
2258
|
|
|
2064
2259
|
/// Try to evaluate a simple callback expression directly without creating a scope.
|
|
2065
2260
|
/// Returns Some(result) for simple patterns like `x => x * 2` or `x => x > 5`.
|
|
2066
|
-
fn eval_simple_callback(
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2261
|
+
fn eval_simple_callback(&self, f: &Value, args: &[Value]) -> Option<Result<Value, EvalError>> {
|
|
2262
|
+
if let Value::Function {
|
|
2263
|
+
formals,
|
|
2264
|
+
body,
|
|
2265
|
+
rest_param,
|
|
2266
|
+
..
|
|
2267
|
+
} = f
|
|
2268
|
+
{
|
|
2072
2269
|
if formals.len() != 1 || rest_param.is_some() {
|
|
2073
2270
|
return None;
|
|
2074
2271
|
}
|
|
@@ -2088,17 +2285,25 @@ impl Evaluator {
|
|
|
2088
2285
|
// Fast path for common patterns
|
|
2089
2286
|
match expr {
|
|
2090
2287
|
// x * constant or x + constant, etc.
|
|
2091
|
-
Expr::Binary {
|
|
2288
|
+
Expr::Binary {
|
|
2289
|
+
left, op, right, ..
|
|
2290
|
+
} => {
|
|
2092
2291
|
let left_val = self.eval_simple_operand(left, param_name, &arg)?;
|
|
2093
2292
|
let right_val = self.eval_simple_operand(right, param_name, &arg)?;
|
|
2094
|
-
Some(
|
|
2293
|
+
Some(
|
|
2294
|
+
self.eval_binop(&left_val, *op, &right_val)
|
|
2295
|
+
.map_err(EvalError::Error),
|
|
2296
|
+
)
|
|
2095
2297
|
}
|
|
2096
2298
|
// Just return the parameter
|
|
2097
|
-
Expr::Ident { name, .. } if name == param_name =>
|
|
2098
|
-
Some(Ok(arg))
|
|
2099
|
-
}
|
|
2299
|
+
Expr::Ident { name, .. } if name == param_name => Some(Ok(arg)),
|
|
2100
2300
|
// Property access: x.prop
|
|
2101
|
-
Expr::Member {
|
|
2301
|
+
Expr::Member {
|
|
2302
|
+
object,
|
|
2303
|
+
prop,
|
|
2304
|
+
optional,
|
|
2305
|
+
..
|
|
2306
|
+
} => {
|
|
2102
2307
|
if let Expr::Ident { name, .. } = object.as_ref() {
|
|
2103
2308
|
if name == param_name {
|
|
2104
2309
|
return self.eval_simple_member(&arg, prop, *optional);
|
|
@@ -2114,7 +2319,12 @@ impl Evaluator {
|
|
|
2114
2319
|
}
|
|
2115
2320
|
|
|
2116
2321
|
/// Evaluate a simple operand (identifier or literal).
|
|
2117
|
-
fn eval_simple_operand(
|
|
2322
|
+
fn eval_simple_operand(
|
|
2323
|
+
&self,
|
|
2324
|
+
expr: &Expr,
|
|
2325
|
+
param_name: &Arc<str>,
|
|
2326
|
+
param_val: &Value,
|
|
2327
|
+
) -> Option<Value> {
|
|
2118
2328
|
match expr {
|
|
2119
2329
|
Expr::Ident { name, .. } if name == param_name => Some(param_val.clone()),
|
|
2120
2330
|
Expr::Literal { value, .. } => match value {
|
|
@@ -2128,20 +2338,27 @@ impl Evaluator {
|
|
|
2128
2338
|
}
|
|
2129
2339
|
|
|
2130
2340
|
/// Evaluate simple member access.
|
|
2131
|
-
fn eval_simple_member(
|
|
2341
|
+
fn eval_simple_member(
|
|
2342
|
+
&self,
|
|
2343
|
+
obj: &Value,
|
|
2344
|
+
property: &MemberProp,
|
|
2345
|
+
_optional: bool,
|
|
2346
|
+
) -> Option<Result<Value, EvalError>> {
|
|
2132
2347
|
match property {
|
|
2133
|
-
MemberProp::Name
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2348
|
+
MemberProp::Name { name, .. } => match obj {
|
|
2349
|
+
Value::Object(o) => {
|
|
2350
|
+
let result = o
|
|
2351
|
+
.borrow()
|
|
2352
|
+
.get(name.as_ref())
|
|
2353
|
+
.cloned()
|
|
2354
|
+
.unwrap_or(Value::Null);
|
|
2355
|
+
Some(Ok(result))
|
|
2356
|
+
}
|
|
2357
|
+
Value::Array(arr) if name.as_ref() == "length" => {
|
|
2358
|
+
Some(Ok(Value::Number(arr.borrow().len() as f64)))
|
|
2143
2359
|
}
|
|
2144
|
-
|
|
2360
|
+
_ => None,
|
|
2361
|
+
},
|
|
2145
2362
|
_ => None,
|
|
2146
2363
|
}
|
|
2147
2364
|
}
|
|
@@ -2160,8 +2377,9 @@ impl Evaluator {
|
|
|
2160
2377
|
#[cfg(feature = "http")]
|
|
2161
2378
|
Value::PromiseConstructor
|
|
2162
2379
|
| Value::Serve
|
|
2163
|
-
| Value::BoundPromiseMethod(_, _)
|
|
2164
|
-
|
|
2380
|
+
| Value::BoundPromiseMethod(_, _) => self.call_func(callee, args),
|
|
2381
|
+
#[cfg(feature = "timers")]
|
|
2382
|
+
Value::TimerBuiltin(_) => self.call_func(callee, args),
|
|
2165
2383
|
Value::OpaqueMethod(_, _) => self.call_func(callee, args),
|
|
2166
2384
|
_ => Ok(Value::Null),
|
|
2167
2385
|
}
|
|
@@ -2169,9 +2387,7 @@ impl Evaluator {
|
|
|
2169
2387
|
|
|
2170
2388
|
fn call_func(&self, f: &Value, args: &[Value]) -> Result<Value, EvalError> {
|
|
2171
2389
|
match f {
|
|
2172
|
-
Value::Native(native_fn) =>
|
|
2173
|
-
native_fn(args).map_err(EvalError::Error)
|
|
2174
|
-
}
|
|
2390
|
+
Value::Native(native_fn) => native_fn(args).map_err(EvalError::Error),
|
|
2175
2391
|
#[cfg(feature = "http")]
|
|
2176
2392
|
Value::PromiseResolver(r) => {
|
|
2177
2393
|
let value = args.first().cloned().unwrap_or(Value::Null);
|
|
@@ -2180,7 +2396,12 @@ impl Evaluator {
|
|
|
2180
2396
|
.map_err(EvalError::Error)?;
|
|
2181
2397
|
for reaction in reactions {
|
|
2182
2398
|
match reaction {
|
|
2183
|
-
crate::promise::Reaction::Then(
|
|
2399
|
+
crate::promise::Reaction::Then(
|
|
2400
|
+
on_fulfilled,
|
|
2401
|
+
on_rejected,
|
|
2402
|
+
ref resolve,
|
|
2403
|
+
ref reject,
|
|
2404
|
+
) => {
|
|
2184
2405
|
let handler_result = if is_fulfilled {
|
|
2185
2406
|
if let Some(ref h) = on_fulfilled {
|
|
2186
2407
|
self.call_func(h, &[val.clone()])
|
|
@@ -2232,8 +2453,10 @@ impl Evaluator {
|
|
|
2232
2453
|
#[cfg(feature = "http")]
|
|
2233
2454
|
Value::Serve => self.run_http_server(args),
|
|
2234
2455
|
Value::CoreFn(f) => {
|
|
2235
|
-
let ca: Result<Vec<tishlang_core::Value>, String> =
|
|
2236
|
-
|
|
2456
|
+
let ca: Result<Vec<tishlang_core::Value>, String> = args
|
|
2457
|
+
.iter()
|
|
2458
|
+
.map(crate::value_convert::eval_to_core)
|
|
2459
|
+
.collect();
|
|
2237
2460
|
let ca = ca.map_err(EvalError::Error)?;
|
|
2238
2461
|
Ok(crate::value_convert::core_to_eval(f(&ca)))
|
|
2239
2462
|
}
|
|
@@ -2243,19 +2466,29 @@ impl Evaluator {
|
|
|
2243
2466
|
Value::BoundPromiseMethod(promise_ref, method) => {
|
|
2244
2467
|
self.run_promise_method(promise_ref, method.as_ref(), args)
|
|
2245
2468
|
}
|
|
2246
|
-
#[cfg(feature = "
|
|
2469
|
+
#[cfg(feature = "timers")]
|
|
2247
2470
|
Value::TimerBuiltin(name) => self.run_timer_builtin(name.as_ref(), args),
|
|
2248
2471
|
Value::OpaqueMethod(opaque, method_name) => {
|
|
2249
2472
|
let method = opaque.get_method(method_name.as_ref()).ok_or_else(|| {
|
|
2250
|
-
EvalError::Error(format!(
|
|
2473
|
+
EvalError::Error(format!(
|
|
2474
|
+
"Method {} not found on {}",
|
|
2475
|
+
method_name,
|
|
2476
|
+
opaque.type_name()
|
|
2477
|
+
))
|
|
2251
2478
|
})?;
|
|
2252
|
-
let core_args: Result<Vec<tishlang_core::Value>, String> =
|
|
2253
|
-
|
|
2479
|
+
let core_args: Result<Vec<tishlang_core::Value>, String> = args
|
|
2480
|
+
.iter()
|
|
2481
|
+
.map(crate::value_convert::eval_to_core)
|
|
2482
|
+
.collect();
|
|
2254
2483
|
let core_args = core_args.map_err(EvalError::Error)?;
|
|
2255
2484
|
let result = method(&core_args);
|
|
2256
2485
|
Ok(crate::value_convert::core_to_eval(result))
|
|
2257
2486
|
}
|
|
2258
|
-
Value::Function {
|
|
2487
|
+
Value::Function {
|
|
2488
|
+
formals,
|
|
2489
|
+
rest_param,
|
|
2490
|
+
body,
|
|
2491
|
+
} => {
|
|
2259
2492
|
let scope = Scope::child(Rc::clone(&self.scope));
|
|
2260
2493
|
{
|
|
2261
2494
|
let mut s = scope.borrow_mut();
|
|
@@ -2289,8 +2522,13 @@ impl Evaluator {
|
|
|
2289
2522
|
}
|
|
2290
2523
|
}
|
|
2291
2524
|
if let Some(ref rest_name) = rest_param {
|
|
2292
|
-
let rest_vals: Vec<Value> =
|
|
2293
|
-
|
|
2525
|
+
let rest_vals: Vec<Value> =
|
|
2526
|
+
args.iter().skip(formals.len()).cloned().collect();
|
|
2527
|
+
s.set(
|
|
2528
|
+
Arc::clone(rest_name),
|
|
2529
|
+
Value::Array(Rc::new(RefCell::new(rest_vals))),
|
|
2530
|
+
true,
|
|
2531
|
+
);
|
|
2294
2532
|
}
|
|
2295
2533
|
}
|
|
2296
2534
|
let mut eval = Evaluator {
|
|
@@ -2304,8 +2542,12 @@ impl Evaluator {
|
|
|
2304
2542
|
Err(EvalError::Return(v)) => Ok(v),
|
|
2305
2543
|
Err(EvalError::Throw(v)) => Err(EvalError::Throw(v)),
|
|
2306
2544
|
Err(EvalError::Error(s)) => Err(EvalError::Error(s)),
|
|
2307
|
-
Err(EvalError::Break) =>
|
|
2308
|
-
|
|
2545
|
+
Err(EvalError::Break) => {
|
|
2546
|
+
Err(EvalError::Error("break outside loop".to_string()))
|
|
2547
|
+
}
|
|
2548
|
+
Err(EvalError::Continue) => {
|
|
2549
|
+
Err(EvalError::Error("continue outside loop".to_string()))
|
|
2550
|
+
}
|
|
2309
2551
|
}
|
|
2310
2552
|
}
|
|
2311
2553
|
_ => Err(EvalError::Error("Not a function".to_string())),
|
|
@@ -2320,14 +2562,15 @@ impl Evaluator {
|
|
|
2320
2562
|
args: &[Value],
|
|
2321
2563
|
) -> Result<Value, EvalError> {
|
|
2322
2564
|
match method {
|
|
2323
|
-
"then" =>
|
|
2324
|
-
promise_ref,
|
|
2325
|
-
|
|
2326
|
-
args.get(1).cloned(),
|
|
2327
|
-
),
|
|
2565
|
+
"then" => {
|
|
2566
|
+
self.run_promise_then_core(promise_ref, args.first().cloned(), args.get(1).cloned())
|
|
2567
|
+
}
|
|
2328
2568
|
"catch" => self.run_promise_then_core(promise_ref, None, args.first().cloned()),
|
|
2329
2569
|
"finally" => self.run_promise_finally(promise_ref, args.first().cloned()),
|
|
2330
|
-
_ => Err(EvalError::Error(format!(
|
|
2570
|
+
_ => Err(EvalError::Error(format!(
|
|
2571
|
+
"Unknown promise method: {}",
|
|
2572
|
+
method
|
|
2573
|
+
))),
|
|
2331
2574
|
}
|
|
2332
2575
|
}
|
|
2333
2576
|
|
|
@@ -2428,7 +2671,12 @@ impl Evaluator {
|
|
|
2428
2671
|
crate::promise::PromiseState::Pending { .. } => {
|
|
2429
2672
|
crate::promise::add_reaction(
|
|
2430
2673
|
state,
|
|
2431
|
-
crate::promise::Reaction::Then(
|
|
2674
|
+
crate::promise::Reaction::Then(
|
|
2675
|
+
on_fulfilled,
|
|
2676
|
+
on_rejected,
|
|
2677
|
+
resolve.clone(),
|
|
2678
|
+
reject.clone(),
|
|
2679
|
+
),
|
|
2432
2680
|
);
|
|
2433
2681
|
}
|
|
2434
2682
|
}
|
|
@@ -2436,7 +2684,7 @@ impl Evaluator {
|
|
|
2436
2684
|
Ok(promise)
|
|
2437
2685
|
}
|
|
2438
2686
|
|
|
2439
|
-
#[cfg(feature = "
|
|
2687
|
+
#[cfg(feature = "timers")]
|
|
2440
2688
|
fn run_timer_builtin(&self, name: &str, args: &[Value]) -> Result<Value, EvalError> {
|
|
2441
2689
|
let callback = args
|
|
2442
2690
|
.first()
|
|
@@ -2457,7 +2705,7 @@ impl Evaluator {
|
|
|
2457
2705
|
Ok(Value::Number(id as f64))
|
|
2458
2706
|
}
|
|
2459
2707
|
|
|
2460
|
-
#[cfg(feature = "
|
|
2708
|
+
#[cfg(feature = "timers")]
|
|
2461
2709
|
fn clear_timeout_native(args: &[Value]) -> Result<Value, String> {
|
|
2462
2710
|
if let Some(Value::Number(n)) = args.first() {
|
|
2463
2711
|
crate::timers::clearTimer(*n as u64);
|
|
@@ -2465,7 +2713,7 @@ impl Evaluator {
|
|
|
2465
2713
|
Ok(Value::Null)
|
|
2466
2714
|
}
|
|
2467
2715
|
|
|
2468
|
-
#[cfg(feature = "
|
|
2716
|
+
#[cfg(feature = "timers")]
|
|
2469
2717
|
fn clear_interval_native(args: &[Value]) -> Result<Value, String> {
|
|
2470
2718
|
if let Some(Value::Number(n)) = args.first() {
|
|
2471
2719
|
crate::timers::clearTimer(*n as u64);
|
|
@@ -2475,7 +2723,7 @@ impl Evaluator {
|
|
|
2475
2723
|
|
|
2476
2724
|
/// Run all due timer callbacks. Called after the script completes so setTimeout/setInterval
|
|
2477
2725
|
/// callbacks run without blocking the main script. Loops until no timers are due.
|
|
2478
|
-
#[cfg(feature = "
|
|
2726
|
+
#[cfg(feature = "timers")]
|
|
2479
2727
|
pub fn run_timer_phase(&mut self) -> Result<(), String> {
|
|
2480
2728
|
const MAX_ITERATIONS: u32 = 1_000_000; // avoid infinite loop if setInterval never cleared
|
|
2481
2729
|
let mut iterations = 0;
|
|
@@ -2537,8 +2785,11 @@ impl Evaluator {
|
|
|
2537
2785
|
let port = port;
|
|
2538
2786
|
std::thread::spawn(move || {
|
|
2539
2787
|
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
|
-
|
|
2788
|
+
if let Ok(mut stream) = std::net::TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
2789
|
+
{
|
|
2790
|
+
let _ = stream.write_all(
|
|
2791
|
+
b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n",
|
|
2792
|
+
);
|
|
2542
2793
|
let _ = stream.shutdown(std::net::Shutdown::Write);
|
|
2543
2794
|
}
|
|
2544
2795
|
});
|
|
@@ -2564,8 +2815,14 @@ impl Evaluator {
|
|
|
2564
2815
|
}
|
|
2565
2816
|
};
|
|
2566
2817
|
|
|
2567
|
-
let (status, headers,
|
|
2568
|
-
|
|
2818
|
+
if let Some((status, headers, file_path)) =
|
|
2819
|
+
crate::http::extract_file_from_response(&response_value)
|
|
2820
|
+
{
|
|
2821
|
+
crate::http::send_file_response(request, status, headers, file_path);
|
|
2822
|
+
} else {
|
|
2823
|
+
let (status, headers, body) = crate::http::value_to_response(&response_value);
|
|
2824
|
+
crate::http::send_response(request, status, headers, body);
|
|
2825
|
+
}
|
|
2569
2826
|
count += 1;
|
|
2570
2827
|
if max_requests.map(|m| count >= m).unwrap_or(false) {
|
|
2571
2828
|
break;
|
|
@@ -2603,13 +2860,17 @@ impl Evaluator {
|
|
|
2603
2860
|
tishlang_ast::DestructPattern::Array(elements) => {
|
|
2604
2861
|
let arr = match value {
|
|
2605
2862
|
Value::Array(a) => a.borrow().clone(),
|
|
2606
|
-
_ =>
|
|
2863
|
+
_ => {
|
|
2864
|
+
return Err(EvalError::Error(
|
|
2865
|
+
"Cannot destructure non-array value".to_string(),
|
|
2866
|
+
))
|
|
2867
|
+
}
|
|
2607
2868
|
};
|
|
2608
2869
|
|
|
2609
2870
|
for (i, elem) in elements.iter().enumerate() {
|
|
2610
2871
|
if let Some(el) = elem {
|
|
2611
2872
|
match el {
|
|
2612
|
-
tishlang_ast::DestructElement::Ident(name) => {
|
|
2873
|
+
tishlang_ast::DestructElement::Ident(name, _) => {
|
|
2613
2874
|
let val = arr.get(i).cloned().unwrap_or(Value::Null);
|
|
2614
2875
|
scope.borrow_mut().set(Arc::clone(name), val, mutable);
|
|
2615
2876
|
}
|
|
@@ -2617,7 +2878,7 @@ impl Evaluator {
|
|
|
2617
2878
|
let val = arr.get(i).cloned().unwrap_or(Value::Null);
|
|
2618
2879
|
Self::bind_destruct_pattern_scoped(scope, nested, &val, mutable)?;
|
|
2619
2880
|
}
|
|
2620
|
-
tishlang_ast::DestructElement::Rest(name) => {
|
|
2881
|
+
tishlang_ast::DestructElement::Rest(name, _) => {
|
|
2621
2882
|
let rest: Vec<Value> = arr.iter().skip(i).cloned().collect();
|
|
2622
2883
|
scope.borrow_mut().set(
|
|
2623
2884
|
Arc::clone(name),
|
|
@@ -2633,19 +2894,23 @@ impl Evaluator {
|
|
|
2633
2894
|
tishlang_ast::DestructPattern::Object(props) => {
|
|
2634
2895
|
let obj = match value {
|
|
2635
2896
|
Value::Object(o) => o.borrow().clone(),
|
|
2636
|
-
_ =>
|
|
2897
|
+
_ => {
|
|
2898
|
+
return Err(EvalError::Error(
|
|
2899
|
+
"Cannot destructure non-object value".to_string(),
|
|
2900
|
+
))
|
|
2901
|
+
}
|
|
2637
2902
|
};
|
|
2638
2903
|
|
|
2639
2904
|
for prop in props {
|
|
2640
2905
|
let val = obj.get(&prop.key).cloned().unwrap_or(Value::Null);
|
|
2641
2906
|
match &prop.value {
|
|
2642
|
-
tishlang_ast::DestructElement::Ident(name) => {
|
|
2907
|
+
tishlang_ast::DestructElement::Ident(name, _) => {
|
|
2643
2908
|
scope.borrow_mut().set(Arc::clone(name), val, mutable);
|
|
2644
2909
|
}
|
|
2645
2910
|
tishlang_ast::DestructElement::Pattern(nested) => {
|
|
2646
2911
|
Self::bind_destruct_pattern_scoped(scope, nested, &val, mutable)?;
|
|
2647
2912
|
}
|
|
2648
|
-
tishlang_ast::DestructElement::Rest(_) => {
|
|
2913
|
+
tishlang_ast::DestructElement::Rest(_, _) => {
|
|
2649
2914
|
return Err(EvalError::Error(
|
|
2650
2915
|
"Rest not supported in object destructuring".to_string(),
|
|
2651
2916
|
));
|
|
@@ -2657,7 +2922,12 @@ impl Evaluator {
|
|
|
2657
2922
|
Ok(())
|
|
2658
2923
|
}
|
|
2659
2924
|
|
|
2660
|
-
fn bind_destruct_pattern(
|
|
2925
|
+
fn bind_destruct_pattern(
|
|
2926
|
+
&mut self,
|
|
2927
|
+
pattern: &tishlang_ast::DestructPattern,
|
|
2928
|
+
value: &Value,
|
|
2929
|
+
mutable: bool,
|
|
2930
|
+
) -> Result<(), EvalError> {
|
|
2661
2931
|
Self::bind_destruct_pattern_scoped(&self.scope, pattern, value, mutable)
|
|
2662
2932
|
}
|
|
2663
2933
|
|
|
@@ -2675,11 +2945,8 @@ impl Evaluator {
|
|
|
2675
2945
|
Some(Value::Bool(b)) => tishlang_core::Value::Bool(*b),
|
|
2676
2946
|
Some(_) => tishlang_core::Value::Number(0.0),
|
|
2677
2947
|
};
|
|
2678
|
-
let out =
|
|
2679
|
-
receiver.as_ref(),
|
|
2680
|
-
search,
|
|
2681
|
-
&position_core,
|
|
2682
|
-
);
|
|
2948
|
+
let out =
|
|
2949
|
+
tishlang_builtins::string::last_index_of_str(receiver.as_ref(), search, &position_core);
|
|
2683
2950
|
match out {
|
|
2684
2951
|
tishlang_core::Value::Number(n) => Value::Number(n),
|
|
2685
2952
|
_ => Value::Number(-1.0),
|
|
@@ -2963,7 +3230,9 @@ impl Evaluator {
|
|
|
2963
3230
|
Ok((Value::Bool(false), rest))
|
|
2964
3231
|
} else {
|
|
2965
3232
|
let end = s
|
|
2966
|
-
.find(|c: char|
|
|
3233
|
+
.find(|c: char| {
|
|
3234
|
+
!c.is_ascii_digit() && c != '-' && c != '+' && c != '.' && c != 'e' && c != 'E'
|
|
3235
|
+
})
|
|
2967
3236
|
.unwrap_or(s.len());
|
|
2968
3237
|
let num_str = &s[..end];
|
|
2969
3238
|
let n: f64 = num_str.parse().map_err(|_| ())?;
|
|
@@ -2991,7 +3260,11 @@ impl Evaluator {
|
|
|
2991
3260
|
.replace('\t', "\\t")
|
|
2992
3261
|
),
|
|
2993
3262
|
Value::Array(arr) => {
|
|
2994
|
-
let inner: Vec<String> = arr
|
|
3263
|
+
let inner: Vec<String> = arr
|
|
3264
|
+
.borrow()
|
|
3265
|
+
.iter()
|
|
3266
|
+
.map(Self::json_stringify_value)
|
|
3267
|
+
.collect();
|
|
2995
3268
|
format!("[{}]", inner.join(","))
|
|
2996
3269
|
}
|
|
2997
3270
|
Value::Object(map) => {
|
|
@@ -3010,7 +3283,14 @@ impl Evaluator {
|
|
|
3010
3283
|
})
|
|
3011
3284
|
.collect();
|
|
3012
3285
|
entries.sort_by(|a, b| a.0.cmp(&b.0));
|
|
3013
|
-
format!(
|
|
3286
|
+
format!(
|
|
3287
|
+
"{{{}}}",
|
|
3288
|
+
entries
|
|
3289
|
+
.into_iter()
|
|
3290
|
+
.map(|(_, s)| s)
|
|
3291
|
+
.collect::<Vec<_>>()
|
|
3292
|
+
.join(",")
|
|
3293
|
+
)
|
|
3014
3294
|
}
|
|
3015
3295
|
Value::Function { .. } | Value::Native(_) => "null".to_string(),
|
|
3016
3296
|
#[cfg(feature = "http")]
|
|
@@ -3021,7 +3301,9 @@ impl Evaluator {
|
|
|
3021
3301
|
| Value::Promise(_)
|
|
3022
3302
|
| Value::PromiseResolver(_)
|
|
3023
3303
|
| Value::PromiseConstructor
|
|
3024
|
-
| Value::BoundPromiseMethod(_, _)
|
|
3304
|
+
| Value::BoundPromiseMethod(_, _) => "null".to_string(),
|
|
3305
|
+
#[cfg(feature = "timers")]
|
|
3306
|
+
Value::TimerBuiltin(_) => "null".to_string(),
|
|
3025
3307
|
#[cfg(feature = "regex")]
|
|
3026
3308
|
Value::RegExp(_) => "null".to_string(),
|
|
3027
3309
|
Value::Opaque(_) | Value::OpaqueMethod(_, _) => "null".to_string(),
|
|
@@ -3041,7 +3323,11 @@ impl Evaluator {
|
|
|
3041
3323
|
|
|
3042
3324
|
fn object_keys(args: &[Value]) -> Result<Value, String> {
|
|
3043
3325
|
if let Some(Value::Object(obj)) = args.first() {
|
|
3044
|
-
let keys: Vec<Value> = obj
|
|
3326
|
+
let keys: Vec<Value> = obj
|
|
3327
|
+
.borrow()
|
|
3328
|
+
.keys()
|
|
3329
|
+
.map(|k| Value::String(Arc::clone(k)))
|
|
3330
|
+
.collect();
|
|
3045
3331
|
Ok(Value::Array(Rc::new(RefCell::new(keys))))
|
|
3046
3332
|
} else {
|
|
3047
3333
|
Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
|
|
@@ -3059,12 +3345,16 @@ impl Evaluator {
|
|
|
3059
3345
|
|
|
3060
3346
|
fn object_entries(args: &[Value]) -> Result<Value, String> {
|
|
3061
3347
|
if let Some(Value::Object(obj)) = args.first() {
|
|
3062
|
-
let entries: Vec<Value> = obj
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3348
|
+
let entries: Vec<Value> = obj
|
|
3349
|
+
.borrow()
|
|
3350
|
+
.iter()
|
|
3351
|
+
.map(|(k, v)| {
|
|
3352
|
+
Value::Array(Rc::new(RefCell::new(vec![
|
|
3353
|
+
Value::String(Arc::clone(k)),
|
|
3354
|
+
v.clone(),
|
|
3355
|
+
])))
|
|
3356
|
+
})
|
|
3357
|
+
.collect();
|
|
3068
3358
|
Ok(Value::Array(Rc::new(RefCell::new(entries))))
|
|
3069
3359
|
} else {
|
|
3070
3360
|
Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
|
|
@@ -3136,7 +3426,10 @@ impl Evaluator {
|
|
|
3136
3426
|
.ok_or_else(|| "Promise.all requires an iterable".to_string())?;
|
|
3137
3427
|
let values: Vec<Value> = match iterable {
|
|
3138
3428
|
Value::Array(arr) => arr.borrow().clone(),
|
|
3139
|
-
Value::String(s) => s
|
|
3429
|
+
Value::String(s) => s
|
|
3430
|
+
.chars()
|
|
3431
|
+
.map(|c| Value::String(c.to_string().into()))
|
|
3432
|
+
.collect(),
|
|
3140
3433
|
_ => return Err("Promise.all requires array or iterable".to_string()),
|
|
3141
3434
|
};
|
|
3142
3435
|
let mut results = Vec::with_capacity(values.len());
|
|
@@ -3146,7 +3439,8 @@ impl Evaluator {
|
|
|
3146
3439
|
crate::promise::PromiseAwaitResult::Fulfilled(x) => results.push(x),
|
|
3147
3440
|
crate::promise::PromiseAwaitResult::Rejected(x) => {
|
|
3148
3441
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3149
|
-
let (_, reject) =
|
|
3442
|
+
let (_, reject) =
|
|
3443
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3150
3444
|
let _ = crate::promise::settle_promise(&reject, x, false);
|
|
3151
3445
|
return Ok(promise);
|
|
3152
3446
|
}
|
|
@@ -3157,7 +3451,8 @@ impl Evaluator {
|
|
|
3157
3451
|
Ok(x) => results.push(crate::value_convert::core_to_eval(x)),
|
|
3158
3452
|
Err(x) => {
|
|
3159
3453
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3160
|
-
let (_, reject) =
|
|
3454
|
+
let (_, reject) =
|
|
3455
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3161
3456
|
let _ = crate::promise::settle_promise(
|
|
3162
3457
|
&reject,
|
|
3163
3458
|
crate::value_convert::core_to_eval(x),
|
|
@@ -3184,7 +3479,10 @@ impl Evaluator {
|
|
|
3184
3479
|
.ok_or_else(|| "Promise.race requires an iterable".to_string())?;
|
|
3185
3480
|
let values: Vec<Value> = match iterable {
|
|
3186
3481
|
Value::Array(arr) => arr.borrow().clone(),
|
|
3187
|
-
Value::String(s) => s
|
|
3482
|
+
Value::String(s) => s
|
|
3483
|
+
.chars()
|
|
3484
|
+
.map(|c| Value::String(c.to_string().into()))
|
|
3485
|
+
.collect(),
|
|
3188
3486
|
_ => return Err("Promise.race requires array or iterable".to_string()),
|
|
3189
3487
|
};
|
|
3190
3488
|
for v in values {
|
|
@@ -3192,7 +3490,8 @@ impl Evaluator {
|
|
|
3192
3490
|
match p.block_until_settled() {
|
|
3193
3491
|
Ok(x) => {
|
|
3194
3492
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3195
|
-
let (resolve, _) =
|
|
3493
|
+
let (resolve, _) =
|
|
3494
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3196
3495
|
crate::promise::settle_promise(
|
|
3197
3496
|
&resolve,
|
|
3198
3497
|
crate::value_convert::core_to_eval(x),
|
|
@@ -3202,7 +3501,8 @@ impl Evaluator {
|
|
|
3202
3501
|
}
|
|
3203
3502
|
Err(x) => {
|
|
3204
3503
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3205
|
-
let (_, reject) =
|
|
3504
|
+
let (_, reject) =
|
|
3505
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3206
3506
|
crate::promise::settle_promise(
|
|
3207
3507
|
&reject,
|
|
3208
3508
|
crate::value_convert::core_to_eval(x),
|
|
@@ -3216,13 +3516,15 @@ impl Evaluator {
|
|
|
3216
3516
|
match crate::promise::block_until_settled(p) {
|
|
3217
3517
|
crate::promise::PromiseAwaitResult::Fulfilled(x) => {
|
|
3218
3518
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3219
|
-
let (resolve, _) =
|
|
3519
|
+
let (resolve, _) =
|
|
3520
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3220
3521
|
crate::promise::settle_promise(&resolve, x, true)?;
|
|
3221
3522
|
return Ok(promise);
|
|
3222
3523
|
}
|
|
3223
3524
|
crate::promise::PromiseAwaitResult::Rejected(x) => {
|
|
3224
3525
|
let (promise, resolve_val, reject_val) = crate::promise::create_promise();
|
|
3225
|
-
let (_, reject) =
|
|
3526
|
+
let (_, reject) =
|
|
3527
|
+
crate::promise::extract_resolvers(&resolve_val, &reject_val);
|
|
3226
3528
|
crate::promise::settle_promise(&reject, x, false)?;
|
|
3227
3529
|
return Ok(promise);
|
|
3228
3530
|
}
|
|
@@ -3239,7 +3541,9 @@ impl Evaluator {
|
|
|
3239
3541
|
for a in args {
|
|
3240
3542
|
cv.push(crate::value_convert::eval_to_core(a)?);
|
|
3241
3543
|
}
|
|
3242
|
-
Ok(crate::value_convert::core_to_eval(
|
|
3544
|
+
Ok(crate::value_convert::core_to_eval(
|
|
3545
|
+
tishlang_runtime::web_socket_client(&cv),
|
|
3546
|
+
))
|
|
3243
3547
|
}
|
|
3244
3548
|
|
|
3245
3549
|
#[cfg(feature = "ws")]
|
|
@@ -3248,7 +3552,9 @@ impl Evaluator {
|
|
|
3248
3552
|
for a in args {
|
|
3249
3553
|
cv.push(crate::value_convert::eval_to_core(a)?);
|
|
3250
3554
|
}
|
|
3251
|
-
Ok(crate::value_convert::core_to_eval(
|
|
3555
|
+
Ok(crate::value_convert::core_to_eval(
|
|
3556
|
+
tishlang_runtime::web_socket_server_construct(&cv),
|
|
3557
|
+
))
|
|
3252
3558
|
}
|
|
3253
3559
|
|
|
3254
3560
|
#[cfg(feature = "ws")]
|
|
@@ -3256,7 +3562,9 @@ impl Evaluator {
|
|
|
3256
3562
|
let conn = args.first().ok_or("wsSend(conn, data) requires conn")?;
|
|
3257
3563
|
let conn_core = crate::value_convert::eval_to_core(conn)?;
|
|
3258
3564
|
let data = args.get(1).map(|v| v.to_string()).unwrap_or_default();
|
|
3259
|
-
Ok(Value::Bool(tishlang_runtime::ws_send_native(
|
|
3565
|
+
Ok(Value::Bool(tishlang_runtime::ws_send_native(
|
|
3566
|
+
&conn_core, &data,
|
|
3567
|
+
)))
|
|
3260
3568
|
}
|
|
3261
3569
|
|
|
3262
3570
|
#[cfg(feature = "ws")]
|
|
@@ -3265,7 +3573,9 @@ impl Evaluator {
|
|
|
3265
3573
|
for a in args {
|
|
3266
3574
|
cv.push(crate::value_convert::eval_to_core(a)?);
|
|
3267
3575
|
}
|
|
3268
|
-
Ok(crate::value_convert::core_to_eval(
|
|
3576
|
+
Ok(crate::value_convert::core_to_eval(
|
|
3577
|
+
tishlang_runtime::ws_broadcast_native(&cv),
|
|
3578
|
+
))
|
|
3269
3579
|
}
|
|
3270
3580
|
|
|
3271
3581
|
#[cfg(feature = "http")]
|
|
@@ -3319,7 +3629,6 @@ impl Evaluator {
|
|
|
3319
3629
|
"await requires the http feature".to_string(),
|
|
3320
3630
|
))
|
|
3321
3631
|
}
|
|
3322
|
-
|
|
3323
3632
|
}
|
|
3324
3633
|
|
|
3325
3634
|
#[derive(Debug)]
|