@tishlang/tish 1.9.2 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/tish +0 -0
- package/crates/js_to_tish/src/transform/expr.rs +8 -6
- package/crates/js_to_tish/src/transform/stmt.rs +12 -13
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cargo_native_registry.rs +4 -1
- package/crates/tish/src/main.rs +11 -8
- package/crates/tish/tests/integration_test.rs +145 -7
- package/crates/tish_ast/src/ast.rs +3 -9
- package/crates/tish_build_utils/src/lib.rs +43 -15
- package/crates/tish_builtins/src/array.rs +2 -3
- package/crates/tish_builtins/src/construct.rs +15 -28
- package/crates/tish_builtins/src/globals.rs +18 -16
- package/crates/tish_builtins/src/helpers.rs +1 -4
- package/crates/tish_builtins/src/lib.rs +1 -0
- package/crates/tish_builtins/src/object.rs +10 -10
- package/crates/tish_builtins/src/string.rs +1 -3
- package/crates/tish_builtins/src/symbol.rs +83 -0
- package/crates/tish_compile/src/codegen.rs +123 -138
- package/crates/tish_compile/src/lib.rs +25 -3
- package/crates/tish_compile/src/resolve.rs +6 -3
- package/crates/tish_compile/src/types.rs +6 -6
- package/crates/tish_compile_js/src/codegen.rs +8 -5
- package/crates/tish_core/src/console_style.rs +9 -0
- package/crates/tish_core/src/json.rs +17 -7
- package/crates/tish_core/src/macros.rs +2 -2
- package/crates/tish_core/src/value.rs +192 -4
- package/crates/tish_cranelift_runtime/Cargo.toml +4 -0
- package/crates/tish_eval/src/eval.rs +135 -73
- package/crates/tish_eval/src/http.rs +18 -12
- package/crates/tish_eval/src/lib.rs +29 -0
- package/crates/tish_eval/src/regex.rs +1 -1
- package/crates/tish_eval/src/value.rs +89 -4
- package/crates/tish_eval/src/value_convert.rs +30 -8
- package/crates/tish_fmt/src/lib.rs +4 -1
- package/crates/tish_lexer/src/lib.rs +7 -2
- package/crates/tish_llvm/src/lib.rs +2 -2
- package/crates/tish_lsp/src/builtin_goto.rs +111 -10
- package/crates/tish_lsp/src/import_goto.rs +35 -22
- package/crates/tish_lsp/src/main.rs +118 -85
- package/crates/tish_native/src/build.rs +187 -10
- package/crates/tish_native/src/lib.rs +92 -8
- package/crates/tish_parser/src/lib.rs +5 -2
- package/crates/tish_parser/src/parser.rs +45 -75
- package/crates/tish_pg/src/error.rs +1 -1
- package/crates/tish_pg/src/lib.rs +61 -73
- package/crates/tish_resolve/src/lib.rs +283 -158
- package/crates/tish_resolve/src/pos.rs +10 -2
- package/crates/tish_runtime/Cargo.toml +3 -0
- package/crates/tish_runtime/src/http.rs +39 -39
- package/crates/tish_runtime/src/http_fetch.rs +12 -12
- package/crates/tish_runtime/src/lib.rs +26 -43
- package/crates/tish_runtime/src/native_promise.rs +0 -11
- package/crates/tish_runtime/src/promise.rs +14 -1
- package/crates/tish_runtime/src/promise_io.rs +1 -4
- package/crates/tish_runtime/src/ws.rs +40 -27
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +10 -8
- package/crates/tish_ui/src/jsx.rs +6 -4
- package/crates/tish_ui/src/lib.rs +2 -2
- package/crates/tish_ui/src/runtime/hooks.rs +5 -15
- package/crates/tish_ui/src/runtime/mod.rs +16 -17
- package/crates/tish_vm/Cargo.toml +2 -0
- package/crates/tish_vm/src/vm.rs +218 -153
- package/crates/tish_wasm/src/lib.rs +33 -7
- package/crates/tish_wasm_runtime/Cargo.toml +4 -1
- package/crates/tish_wasm_runtime/src/lib.rs +2 -1
- package/crates/tishlang_cargo_bindgen/src/classify.rs +1 -3
- package/crates/tishlang_cargo_bindgen/src/discover.rs +10 -5
- package/crates/tishlang_cargo_bindgen/src/infer.rs +18 -8
- package/crates/tishlang_cargo_bindgen/src/lib.rs +25 -26
- package/crates/tishlang_cargo_bindgen/src/main.rs +41 -38
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +4 -1
- package/justfile +3 -3
- package/package.json +1 -1
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- package/platform/win32-x64/tish.exe +0 -0
|
@@ -15,7 +15,11 @@ use tishlang_ast::{
|
|
|
15
15
|
|
|
16
16
|
#[cfg(any(feature = "fs", feature = "process"))]
|
|
17
17
|
use crate::natives;
|
|
18
|
-
use
|
|
18
|
+
use ahash::AHashMap;
|
|
19
|
+
|
|
20
|
+
use crate::value::{
|
|
21
|
+
eval_object_get, eval_object_has, eval_object_set, EvalObjectData, PropMap, Value,
|
|
22
|
+
};
|
|
19
23
|
|
|
20
24
|
struct Scope {
|
|
21
25
|
vars: PropMap,
|
|
@@ -98,7 +102,7 @@ impl Evaluator {
|
|
|
98
102
|
console.insert("error".into(), Value::Native(natives::console_error));
|
|
99
103
|
s.set(
|
|
100
104
|
"console".into(),
|
|
101
|
-
Value::
|
|
105
|
+
Value::object(console),
|
|
102
106
|
true,
|
|
103
107
|
);
|
|
104
108
|
s.set("parseInt".into(), Value::Native(natives::parse_int), true);
|
|
@@ -109,7 +113,11 @@ impl Evaluator {
|
|
|
109
113
|
);
|
|
110
114
|
s.set("decodeURI".into(), Value::Native(natives::decode_uri), true);
|
|
111
115
|
s.set("encodeURI".into(), Value::Native(natives::encode_uri), true);
|
|
112
|
-
s.set(
|
|
116
|
+
s.set(
|
|
117
|
+
"htmlEscape".into(),
|
|
118
|
+
Value::Native(natives::html_escape),
|
|
119
|
+
true,
|
|
120
|
+
);
|
|
113
121
|
s.set(
|
|
114
122
|
"Boolean".into(),
|
|
115
123
|
Value::Native(natives::boolean_native),
|
|
@@ -140,7 +148,7 @@ impl Evaluator {
|
|
|
140
148
|
math.insert("E".into(), Value::Number(std::f64::consts::E));
|
|
141
149
|
s.set(
|
|
142
150
|
"Math".into(),
|
|
143
|
-
Value::
|
|
151
|
+
Value::object(math),
|
|
144
152
|
true,
|
|
145
153
|
);
|
|
146
154
|
|
|
@@ -152,7 +160,7 @@ impl Evaluator {
|
|
|
152
160
|
);
|
|
153
161
|
s.set(
|
|
154
162
|
"JSON".into(),
|
|
155
|
-
Value::
|
|
163
|
+
Value::object(json),
|
|
156
164
|
true,
|
|
157
165
|
);
|
|
158
166
|
|
|
@@ -167,7 +175,7 @@ impl Evaluator {
|
|
|
167
175
|
);
|
|
168
176
|
s.set(
|
|
169
177
|
"Object".into(),
|
|
170
|
-
Value::
|
|
178
|
+
Value::object(object),
|
|
171
179
|
true,
|
|
172
180
|
);
|
|
173
181
|
|
|
@@ -175,7 +183,7 @@ impl Evaluator {
|
|
|
175
183
|
array_obj.insert("isArray".into(), Value::Native(natives::array_is_array));
|
|
176
184
|
s.set(
|
|
177
185
|
"Array".into(),
|
|
178
|
-
Value::
|
|
186
|
+
Value::object(array_obj),
|
|
179
187
|
true,
|
|
180
188
|
);
|
|
181
189
|
|
|
@@ -186,7 +194,7 @@ impl Evaluator {
|
|
|
186
194
|
);
|
|
187
195
|
s.set(
|
|
188
196
|
"String".into(),
|
|
189
|
-
Value::
|
|
197
|
+
Value::object(string_obj),
|
|
190
198
|
true,
|
|
191
199
|
);
|
|
192
200
|
|
|
@@ -194,10 +202,15 @@ impl Evaluator {
|
|
|
194
202
|
date.insert("now".into(), Value::Native(natives::date_now));
|
|
195
203
|
s.set(
|
|
196
204
|
"Date".into(),
|
|
197
|
-
Value::
|
|
205
|
+
Value::object(date),
|
|
198
206
|
true,
|
|
199
207
|
);
|
|
200
208
|
|
|
209
|
+
s.set(
|
|
210
|
+
"Symbol".into(),
|
|
211
|
+
crate::value_convert::core_to_eval(tishlang_builtins::symbol::symbol_object()),
|
|
212
|
+
true,
|
|
213
|
+
);
|
|
201
214
|
s.set(
|
|
202
215
|
"Uint8Array".into(),
|
|
203
216
|
crate::value_convert::core_to_eval(
|
|
@@ -249,7 +262,11 @@ impl Evaluator {
|
|
|
249
262
|
#[cfg(feature = "http")]
|
|
250
263
|
{
|
|
251
264
|
s.set("fetch".into(), Value::Native(Self::fetch_native), true);
|
|
252
|
-
s.set(
|
|
265
|
+
s.set(
|
|
266
|
+
"fetchAll".into(),
|
|
267
|
+
Value::Native(Self::fetch_all_native),
|
|
268
|
+
true,
|
|
269
|
+
);
|
|
253
270
|
s.set("Promise".into(), Value::PromiseConstructor, true);
|
|
254
271
|
s.set("serve".into(), Value::Serve, true);
|
|
255
272
|
}
|
|
@@ -588,7 +605,7 @@ impl Evaluator {
|
|
|
588
605
|
for spec in specifiers {
|
|
589
606
|
match spec {
|
|
590
607
|
ImportSpecifier::Named { name, alias, .. } => {
|
|
591
|
-
let v = exports.get(name.as_ref()).ok_or_else(|| {
|
|
608
|
+
let v = exports.strings.get(name.as_ref()).ok_or_else(|| {
|
|
592
609
|
EvalError::Error(format!("Module does not export '{}'", name))
|
|
593
610
|
})?;
|
|
594
611
|
let bind = alias.as_deref().unwrap_or(name.as_ref());
|
|
@@ -598,7 +615,7 @@ impl Evaluator {
|
|
|
598
615
|
scope.set(Arc::clone(name), exports_val.clone(), false);
|
|
599
616
|
}
|
|
600
617
|
ImportSpecifier::Default { name, .. } => {
|
|
601
|
-
let v = exports.get("default").ok_or_else(|| {
|
|
618
|
+
let v = exports.strings.get("default").ok_or_else(|| {
|
|
602
619
|
EvalError::Error("Module does not have default export".to_string())
|
|
603
620
|
})?;
|
|
604
621
|
scope.set(Arc::clone(name), v.clone(), false);
|
|
@@ -619,9 +636,9 @@ impl Evaluator {
|
|
|
619
636
|
}
|
|
620
637
|
Ok(Value::Null)
|
|
621
638
|
}
|
|
622
|
-
Statement::TypeAlias { .. }
|
|
623
|
-
|
|
624
|
-
}
|
|
639
|
+
Statement::TypeAlias { .. }
|
|
640
|
+
| Statement::DeclareVar { .. }
|
|
641
|
+
| Statement::DeclareFun { .. } => Ok(Value::Null),
|
|
625
642
|
}
|
|
626
643
|
}
|
|
627
644
|
|
|
@@ -694,7 +711,7 @@ impl Evaluator {
|
|
|
694
711
|
}
|
|
695
712
|
*self.current_dir.borrow_mut() = parent_dir;
|
|
696
713
|
self.scope = prev_scope;
|
|
697
|
-
let exports_val = Value::
|
|
714
|
+
let exports_val = Value::object(exports);
|
|
698
715
|
self.module_cache
|
|
699
716
|
.borrow_mut()
|
|
700
717
|
.insert(path, exports_val.clone());
|
|
@@ -743,7 +760,7 @@ impl Evaluator {
|
|
|
743
760
|
exports.insert("isDir".into(), Value::Native(natives::is_dir));
|
|
744
761
|
exports.insert("readDir".into(), Value::Native(natives::read_dir));
|
|
745
762
|
exports.insert("mkdir".into(), Value::Native(natives::mkdir));
|
|
746
|
-
return Ok(Value::
|
|
763
|
+
return Ok(Value::object(exports));
|
|
747
764
|
}
|
|
748
765
|
#[cfg(not(feature = "fs"))]
|
|
749
766
|
{
|
|
@@ -760,7 +777,7 @@ impl Evaluator {
|
|
|
760
777
|
exports.insert("fetchAll".into(), Value::Native(Self::fetch_all_native));
|
|
761
778
|
exports.insert("serve".into(), Value::Serve);
|
|
762
779
|
exports.insert("Promise".into(), Value::PromiseConstructor);
|
|
763
|
-
return Ok(Value::
|
|
780
|
+
return Ok(Value::object(exports));
|
|
764
781
|
}
|
|
765
782
|
#[cfg(not(feature = "http"))]
|
|
766
783
|
{
|
|
@@ -789,7 +806,7 @@ impl Evaluator {
|
|
|
789
806
|
"clearInterval".into(),
|
|
790
807
|
Value::Native(Self::clear_interval_native),
|
|
791
808
|
);
|
|
792
|
-
return Ok(Value::
|
|
809
|
+
return Ok(Value::object(exports));
|
|
793
810
|
}
|
|
794
811
|
#[cfg(not(feature = "timers"))]
|
|
795
812
|
{
|
|
@@ -812,7 +829,7 @@ impl Evaluator {
|
|
|
812
829
|
"wsBroadcast".into(),
|
|
813
830
|
Value::Native(Self::ws_broadcast_native),
|
|
814
831
|
);
|
|
815
|
-
return Ok(Value::
|
|
832
|
+
return Ok(Value::object(exports));
|
|
816
833
|
}
|
|
817
834
|
#[cfg(not(feature = "ws"))]
|
|
818
835
|
{
|
|
@@ -839,19 +856,19 @@ impl Evaluator {
|
|
|
839
856
|
.collect();
|
|
840
857
|
exports.insert(
|
|
841
858
|
"env".into(),
|
|
842
|
-
Value::
|
|
859
|
+
Value::object(env_obj.clone()),
|
|
843
860
|
);
|
|
844
861
|
let mut process_obj = PropMap::default();
|
|
845
862
|
process_obj.insert("exit".into(), Value::Native(natives::process_exit));
|
|
846
863
|
process_obj.insert("cwd".into(), Value::Native(natives::process_cwd));
|
|
847
864
|
process_obj.insert("exec".into(), Value::Native(natives::process_exec));
|
|
848
865
|
process_obj.insert("argv".into(), Value::Array(Rc::new(RefCell::new(argv))));
|
|
849
|
-
process_obj.insert("env".into(), Value::
|
|
866
|
+
process_obj.insert("env".into(), Value::object(env_obj));
|
|
850
867
|
exports.insert(
|
|
851
868
|
"process".into(),
|
|
852
|
-
Value::
|
|
869
|
+
Value::object(process_obj),
|
|
853
870
|
);
|
|
854
|
-
return Ok(Value::
|
|
871
|
+
return Ok(Value::object(exports));
|
|
855
872
|
}
|
|
856
873
|
#[cfg(not(feature = "process"))]
|
|
857
874
|
{
|
|
@@ -875,9 +892,13 @@ impl Evaluator {
|
|
|
875
892
|
Value::Object(m) => m.borrow().clone(),
|
|
876
893
|
_ => return Err(EvalError::Error("Built-in module must be object".into())),
|
|
877
894
|
};
|
|
878
|
-
exports
|
|
879
|
-
|
|
880
|
-
|
|
895
|
+
exports
|
|
896
|
+
.strings
|
|
897
|
+
.get(export_name)
|
|
898
|
+
.cloned()
|
|
899
|
+
.ok_or_else(|| {
|
|
900
|
+
EvalError::Error(format!("Module {} does not export '{}'", spec, export_name))
|
|
901
|
+
})
|
|
881
902
|
}
|
|
882
903
|
|
|
883
904
|
fn eval_expr(&self, expr: &Expr) -> Result<Value, EvalError> {
|
|
@@ -1747,23 +1768,35 @@ impl Evaluator {
|
|
|
1747
1768
|
Ok(Value::Array(Rc::new(RefCell::new(vals))))
|
|
1748
1769
|
}
|
|
1749
1770
|
Expr::Object { props, .. } => {
|
|
1750
|
-
let mut
|
|
1771
|
+
let mut data = EvalObjectData::default();
|
|
1751
1772
|
for prop in props {
|
|
1752
1773
|
match prop {
|
|
1753
1774
|
tishlang_ast::ObjectProp::KeyValue(k, v) => {
|
|
1754
|
-
|
|
1775
|
+
data
|
|
1776
|
+
.strings
|
|
1777
|
+
.insert(Arc::clone(k), self.eval_expr(v)?);
|
|
1755
1778
|
}
|
|
1756
1779
|
tishlang_ast::ObjectProp::Spread(e) => {
|
|
1757
1780
|
let spread_val = self.eval_expr(e)?;
|
|
1758
1781
|
if let Value::Object(obj) = spread_val {
|
|
1759
|
-
|
|
1760
|
-
|
|
1782
|
+
let b = obj.borrow();
|
|
1783
|
+
for (k, v) in b.strings.iter() {
|
|
1784
|
+
data.strings.insert(Arc::clone(k), v.clone());
|
|
1785
|
+
}
|
|
1786
|
+
if let Some(ref sm) = b.symbols {
|
|
1787
|
+
if data.symbols.is_none() {
|
|
1788
|
+
data.symbols = Some(AHashMap::default());
|
|
1789
|
+
}
|
|
1790
|
+
let dm = data.symbols.as_mut().unwrap();
|
|
1791
|
+
for (id, v) in sm.iter() {
|
|
1792
|
+
dm.insert(*id, v.clone());
|
|
1793
|
+
}
|
|
1761
1794
|
}
|
|
1762
1795
|
}
|
|
1763
1796
|
}
|
|
1764
1797
|
}
|
|
1765
1798
|
}
|
|
1766
|
-
Ok(Value::Object(Rc::new(RefCell::new(
|
|
1799
|
+
Ok(Value::Object(Rc::new(RefCell::new(data))))
|
|
1767
1800
|
}
|
|
1768
1801
|
Expr::Assign { name, value, .. } => {
|
|
1769
1802
|
let v = self.eval_expr(value)?;
|
|
@@ -1794,6 +1827,7 @@ impl Evaluator {
|
|
|
1794
1827
|
Value::Null => "null".into(),
|
|
1795
1828
|
Value::Array(_) => "object".into(),
|
|
1796
1829
|
Value::Object(_) => "object".into(),
|
|
1830
|
+
Value::Symbol(_) => "symbol".into(),
|
|
1797
1831
|
Value::Function { .. } | Value::Native(_) => "function".into(),
|
|
1798
1832
|
Value::CoreFn(_) => "function".into(),
|
|
1799
1833
|
#[cfg(feature = "http")]
|
|
@@ -1924,7 +1958,9 @@ impl Evaluator {
|
|
|
1924
1958
|
let val = self.eval_expr(value)?;
|
|
1925
1959
|
match obj_val {
|
|
1926
1960
|
Value::Object(map) => {
|
|
1927
|
-
map.borrow_mut()
|
|
1961
|
+
map.borrow_mut()
|
|
1962
|
+
.strings
|
|
1963
|
+
.insert(Arc::clone(prop), val.clone());
|
|
1928
1964
|
Ok(val)
|
|
1929
1965
|
}
|
|
1930
1966
|
_ => Err(EvalError::Error(format!(
|
|
@@ -1954,16 +1990,9 @@ impl Evaluator {
|
|
|
1954
1990
|
arr_mut[idx] = val.clone();
|
|
1955
1991
|
Ok(val)
|
|
1956
1992
|
}
|
|
1957
|
-
Value::Object(
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
Value::String(s) => Arc::clone(s),
|
|
1961
|
-
_ => return Err(EvalError::Error(format!(
|
|
1962
|
-
"Object key must be string or number, got {:?}",
|
|
1963
|
-
idx_val
|
|
1964
|
-
))),
|
|
1965
|
-
};
|
|
1966
|
-
map.borrow_mut().insert(key, val.clone());
|
|
1993
|
+
Value::Object(_) => {
|
|
1994
|
+
eval_object_set(&obj_val, &idx_val, val.clone())
|
|
1995
|
+
.map_err(EvalError::Error)?;
|
|
1967
1996
|
Ok(val)
|
|
1968
1997
|
}
|
|
1969
1998
|
_ => Err(EvalError::Error(format!(
|
|
@@ -2051,14 +2080,19 @@ impl Evaluator {
|
|
|
2051
2080
|
BinOp::Shl => self.binop_int32(l, r, |a, b| Value::Number((a << b) as f64)),
|
|
2052
2081
|
BinOp::Shr => self.binop_int32(l, r, |a, b| Value::Number((a >> b) as f64)),
|
|
2053
2082
|
BinOp::In => {
|
|
2054
|
-
let key: Arc<str> = match l {
|
|
2055
|
-
Value::String(s) => Arc::clone(s),
|
|
2056
|
-
Value::Number(n) => n.to_string().into(),
|
|
2057
|
-
_ => return Err(format!("'in' requires string or number key, got {:?}", l)),
|
|
2058
|
-
};
|
|
2059
2083
|
let ok = match r {
|
|
2060
|
-
Value::Object(
|
|
2084
|
+
Value::Object(_) => eval_object_has(r, l),
|
|
2061
2085
|
Value::Array(arr) => {
|
|
2086
|
+
let key: Arc<str> = match l {
|
|
2087
|
+
Value::String(s) => Arc::clone(s),
|
|
2088
|
+
Value::Number(n) => n.to_string().into(),
|
|
2089
|
+
_ => {
|
|
2090
|
+
return Err(format!(
|
|
2091
|
+
"'in' requires string or number key on array, got {:?}",
|
|
2092
|
+
l
|
|
2093
|
+
))
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2062
2096
|
key.as_ref() == "length"
|
|
2063
2097
|
|| key
|
|
2064
2098
|
.parse::<usize>()
|
|
@@ -2349,6 +2383,7 @@ impl Evaluator {
|
|
|
2349
2383
|
Value::Object(o) => {
|
|
2350
2384
|
let result = o
|
|
2351
2385
|
.borrow()
|
|
2386
|
+
.strings
|
|
2352
2387
|
.get(name.as_ref())
|
|
2353
2388
|
.cloned()
|
|
2354
2389
|
.unwrap_or(Value::Null);
|
|
@@ -2366,8 +2401,13 @@ impl Evaluator {
|
|
|
2366
2401
|
/// Host `new`: `__construct` on objects; otherwise same callables as `call_func`, else null.
|
|
2367
2402
|
fn construct_value(&self, callee: &Value, args: &[Value]) -> Result<Value, EvalError> {
|
|
2368
2403
|
if let Value::Object(o) = callee {
|
|
2369
|
-
if let Some(ctor) = o
|
|
2370
|
-
|
|
2404
|
+
if let Some(ctor) = o
|
|
2405
|
+
.borrow()
|
|
2406
|
+
.strings
|
|
2407
|
+
.get("__construct")
|
|
2408
|
+
.cloned()
|
|
2409
|
+
{
|
|
2410
|
+
return self.call_func(&ctor, args);
|
|
2371
2411
|
}
|
|
2372
2412
|
}
|
|
2373
2413
|
match callee {
|
|
@@ -2375,9 +2415,9 @@ impl Evaluator {
|
|
|
2375
2415
|
self.call_func(callee, args)
|
|
2376
2416
|
}
|
|
2377
2417
|
#[cfg(feature = "http")]
|
|
2378
|
-
Value::PromiseConstructor
|
|
2379
|
-
|
|
2380
|
-
|
|
2418
|
+
Value::PromiseConstructor | Value::Serve | Value::BoundPromiseMethod(_, _) => {
|
|
2419
|
+
self.call_func(callee, args)
|
|
2420
|
+
}
|
|
2381
2421
|
#[cfg(feature = "timers")]
|
|
2382
2422
|
Value::TimerBuiltin(_) => self.call_func(callee, args),
|
|
2383
2423
|
Value::OpaqueMethod(_, _) => self.call_func(callee, args),
|
|
@@ -2387,6 +2427,12 @@ impl Evaluator {
|
|
|
2387
2427
|
|
|
2388
2428
|
fn call_func(&self, f: &Value, args: &[Value]) -> Result<Value, EvalError> {
|
|
2389
2429
|
match f {
|
|
2430
|
+
Value::Object(o) => {
|
|
2431
|
+
if let Some(call) = o.borrow().strings.get("__call").cloned() {
|
|
2432
|
+
return self.call_func(&call, args);
|
|
2433
|
+
}
|
|
2434
|
+
Err(EvalError::Error("Not a function".to_string()))
|
|
2435
|
+
}
|
|
2390
2436
|
Value::Native(native_fn) => native_fn(args).map_err(EvalError::Error),
|
|
2391
2437
|
#[cfg(feature = "http")]
|
|
2392
2438
|
Value::PromiseResolver(r) => {
|
|
@@ -2805,13 +2851,13 @@ impl Evaluator {
|
|
|
2805
2851
|
let mut err_obj: PropMap = PropMap::with_capacity(2);
|
|
2806
2852
|
err_obj.insert(Arc::from("status"), Value::Number(500.0));
|
|
2807
2853
|
err_obj.insert(Arc::from("body"), Value::String(v.to_string().into()));
|
|
2808
|
-
Value::
|
|
2854
|
+
Value::object(err_obj)
|
|
2809
2855
|
}
|
|
2810
2856
|
Err(e) => {
|
|
2811
2857
|
let mut err_obj: PropMap = PropMap::with_capacity(2);
|
|
2812
2858
|
err_obj.insert(Arc::from("status"), Value::Number(500.0));
|
|
2813
2859
|
err_obj.insert(Arc::from("body"), Value::String(e.to_string().into()));
|
|
2814
|
-
Value::
|
|
2860
|
+
Value::object(err_obj)
|
|
2815
2861
|
}
|
|
2816
2862
|
};
|
|
2817
2863
|
|
|
@@ -2902,7 +2948,11 @@ impl Evaluator {
|
|
|
2902
2948
|
};
|
|
2903
2949
|
|
|
2904
2950
|
for prop in props {
|
|
2905
|
-
let val = obj
|
|
2951
|
+
let val = obj
|
|
2952
|
+
.strings
|
|
2953
|
+
.get(prop.key.as_ref())
|
|
2954
|
+
.cloned()
|
|
2955
|
+
.unwrap_or(Value::Null);
|
|
2906
2956
|
match &prop.value {
|
|
2907
2957
|
tishlang_ast::DestructElement::Ident(name, _) => {
|
|
2908
2958
|
scope.borrow_mut().set(Arc::clone(name), val, mutable);
|
|
@@ -2955,7 +3005,12 @@ impl Evaluator {
|
|
|
2955
3005
|
|
|
2956
3006
|
fn get_prop(&self, obj: &Value, key: &str) -> Result<Value, String> {
|
|
2957
3007
|
match obj {
|
|
2958
|
-
Value::Object(map) => Ok(map
|
|
3008
|
+
Value::Object(map) => Ok(map
|
|
3009
|
+
.borrow()
|
|
3010
|
+
.strings
|
|
3011
|
+
.get(key)
|
|
3012
|
+
.cloned()
|
|
3013
|
+
.unwrap_or(Value::Null)),
|
|
2959
3014
|
Value::Array(arr) => {
|
|
2960
3015
|
if key == "length" {
|
|
2961
3016
|
Ok(Value::Number(arr.borrow().len() as f64))
|
|
@@ -3034,14 +3089,7 @@ impl Evaluator {
|
|
|
3034
3089
|
};
|
|
3035
3090
|
Ok(arr.borrow().get(idx).cloned().unwrap_or(Value::Null))
|
|
3036
3091
|
}
|
|
3037
|
-
Value::Object(
|
|
3038
|
-
let key: Arc<str> = match index {
|
|
3039
|
-
Value::Number(n) => n.to_string().into(),
|
|
3040
|
-
Value::String(s) => Arc::clone(s),
|
|
3041
|
-
_ => return Ok(Value::Null),
|
|
3042
|
-
};
|
|
3043
|
-
Ok(map.borrow().get(&key).cloned().unwrap_or(Value::Null))
|
|
3044
|
-
}
|
|
3092
|
+
Value::Object(_) => Ok(eval_object_get(obj, index).unwrap_or(Value::Null)),
|
|
3045
3093
|
#[cfg(feature = "http")]
|
|
3046
3094
|
Value::Promise(_) | Value::CorePromise(_) => {
|
|
3047
3095
|
let key = match index {
|
|
@@ -3154,7 +3202,7 @@ impl Evaluator {
|
|
|
3154
3202
|
fn json_parse_object(s: &str) -> Result<Value, ()> {
|
|
3155
3203
|
let s = s[1..].trim_start();
|
|
3156
3204
|
if s.starts_with('}') {
|
|
3157
|
-
return Ok(Value::
|
|
3205
|
+
return Ok(Value::object(PropMap::default()));
|
|
3158
3206
|
}
|
|
3159
3207
|
let mut map = PropMap::default();
|
|
3160
3208
|
let mut rest = s;
|
|
@@ -3183,7 +3231,7 @@ impl Evaluator {
|
|
|
3183
3231
|
}
|
|
3184
3232
|
rest = rest[1..].trim_start();
|
|
3185
3233
|
}
|
|
3186
|
-
Ok(Value::
|
|
3234
|
+
Ok(Value::object(map))
|
|
3187
3235
|
}
|
|
3188
3236
|
|
|
3189
3237
|
fn json_parse_one(s: &str) -> Result<(Value, &str), ()> {
|
|
@@ -3270,6 +3318,7 @@ impl Evaluator {
|
|
|
3270
3318
|
Value::Object(map) => {
|
|
3271
3319
|
let mut entries: Vec<_> = map
|
|
3272
3320
|
.borrow()
|
|
3321
|
+
.strings
|
|
3273
3322
|
.iter()
|
|
3274
3323
|
.map(|(k, v)| {
|
|
3275
3324
|
(
|
|
@@ -3292,6 +3341,7 @@ impl Evaluator {
|
|
|
3292
3341
|
.join(",")
|
|
3293
3342
|
)
|
|
3294
3343
|
}
|
|
3344
|
+
Value::Symbol(_) => "null".to_string(),
|
|
3295
3345
|
Value::Function { .. } | Value::Native(_) => "null".to_string(),
|
|
3296
3346
|
#[cfg(feature = "http")]
|
|
3297
3347
|
Value::CorePromise(_) => "null".to_string(),
|
|
@@ -3325,6 +3375,7 @@ impl Evaluator {
|
|
|
3325
3375
|
if let Some(Value::Object(obj)) = args.first() {
|
|
3326
3376
|
let keys: Vec<Value> = obj
|
|
3327
3377
|
.borrow()
|
|
3378
|
+
.strings
|
|
3328
3379
|
.keys()
|
|
3329
3380
|
.map(|k| Value::String(Arc::clone(k)))
|
|
3330
3381
|
.collect();
|
|
@@ -3336,7 +3387,7 @@ impl Evaluator {
|
|
|
3336
3387
|
|
|
3337
3388
|
fn object_values(args: &[Value]) -> Result<Value, String> {
|
|
3338
3389
|
if let Some(Value::Object(obj)) = args.first() {
|
|
3339
|
-
let values: Vec<Value> = obj.borrow().values().cloned().collect();
|
|
3390
|
+
let values: Vec<Value> = obj.borrow().strings.values().cloned().collect();
|
|
3340
3391
|
Ok(Value::Array(Rc::new(RefCell::new(values))))
|
|
3341
3392
|
} else {
|
|
3342
3393
|
Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
|
|
@@ -3347,6 +3398,7 @@ impl Evaluator {
|
|
|
3347
3398
|
if let Some(Value::Object(obj)) = args.first() {
|
|
3348
3399
|
let entries: Vec<Value> = obj
|
|
3349
3400
|
.borrow()
|
|
3401
|
+
.strings
|
|
3350
3402
|
.iter()
|
|
3351
3403
|
.map(|(k, v)| {
|
|
3352
3404
|
Value::Array(Rc::new(RefCell::new(vec![
|
|
@@ -3366,8 +3418,18 @@ impl Evaluator {
|
|
|
3366
3418
|
let mut t = target.borrow_mut();
|
|
3367
3419
|
for src in args.iter().skip(1) {
|
|
3368
3420
|
if let Value::Object(src_obj) = src {
|
|
3369
|
-
|
|
3370
|
-
|
|
3421
|
+
let s = src_obj.borrow();
|
|
3422
|
+
for (k, v) in s.strings.iter() {
|
|
3423
|
+
t.strings.insert(Arc::clone(k), v.clone());
|
|
3424
|
+
}
|
|
3425
|
+
if let Some(ref sm) = s.symbols {
|
|
3426
|
+
if t.symbols.is_none() {
|
|
3427
|
+
t.symbols = Some(AHashMap::default());
|
|
3428
|
+
}
|
|
3429
|
+
let tm = t.symbols.as_mut().unwrap();
|
|
3430
|
+
for (id, v) in sm.iter() {
|
|
3431
|
+
tm.insert(*id, v.clone());
|
|
3432
|
+
}
|
|
3371
3433
|
}
|
|
3372
3434
|
}
|
|
3373
3435
|
}
|
|
@@ -3390,9 +3452,9 @@ impl Evaluator {
|
|
|
3390
3452
|
}
|
|
3391
3453
|
}
|
|
3392
3454
|
}
|
|
3393
|
-
Ok(Value::
|
|
3455
|
+
Ok(Value::object(map))
|
|
3394
3456
|
} else {
|
|
3395
|
-
Ok(Value::
|
|
3457
|
+
Ok(Value::object(PropMap::default()))
|
|
3396
3458
|
}
|
|
3397
3459
|
}
|
|
3398
3460
|
|
|
@@ -46,16 +46,13 @@ pub fn request_to_value(request: &mut tiny_http::Request) -> Value {
|
|
|
46
46
|
Value::String(header.value.as_str().into()),
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
-
obj.insert(
|
|
50
|
-
Arc::from("headers"),
|
|
51
|
-
Value::Object(std::rc::Rc::new(std::cell::RefCell::new(headers_obj))),
|
|
52
|
-
);
|
|
49
|
+
obj.insert(Arc::from("headers"), Value::object(headers_obj));
|
|
53
50
|
|
|
54
51
|
let mut body = String::new();
|
|
55
52
|
let _ = request.as_reader().read_to_string(&mut body);
|
|
56
53
|
obj.insert(Arc::from("body"), Value::String(body.into()));
|
|
57
54
|
|
|
58
|
-
Value::
|
|
55
|
+
Value::object(obj)
|
|
59
56
|
}
|
|
60
57
|
|
|
61
58
|
/// Extract response data from a Tish Value object.
|
|
@@ -68,7 +65,8 @@ pub fn value_to_response(value: &Value) -> (u16, Vec<(String, String)>, String)
|
|
|
68
65
|
let obj_ref = obj.borrow();
|
|
69
66
|
|
|
70
67
|
let status = obj_ref
|
|
71
|
-
.
|
|
68
|
+
.strings
|
|
69
|
+
.get("status")
|
|
72
70
|
.and_then(|v| match v {
|
|
73
71
|
Value::Number(n) => Some(*n as u16),
|
|
74
72
|
_ => None,
|
|
@@ -76,15 +74,18 @@ pub fn value_to_response(value: &Value) -> (u16, Vec<(String, String)>, String)
|
|
|
76
74
|
.unwrap_or(default_status);
|
|
77
75
|
|
|
78
76
|
let body = obj_ref
|
|
79
|
-
.
|
|
77
|
+
.strings
|
|
78
|
+
.get("body")
|
|
80
79
|
.map(|v| v.to_string())
|
|
81
80
|
.unwrap_or_default();
|
|
82
81
|
|
|
83
82
|
let headers = obj_ref
|
|
84
|
-
.
|
|
83
|
+
.strings
|
|
84
|
+
.get("headers")
|
|
85
85
|
.and_then(|v| match v {
|
|
86
86
|
Value::Object(h) => Some(
|
|
87
87
|
h.borrow()
|
|
88
|
+
.strings
|
|
88
89
|
.iter()
|
|
89
90
|
.map(|(k, v)| (k.to_string(), v.to_string()))
|
|
90
91
|
.collect(),
|
|
@@ -103,28 +104,33 @@ pub fn value_to_response(value: &Value) -> (u16, Vec<(String, String)>, String)
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
/// If the response value has a `file` key, stream that path (binary-safe). Matches `tishlang_runtime` HTTP behavior.
|
|
106
|
-
pub(crate) fn extract_file_from_response(
|
|
107
|
+
pub(crate) fn extract_file_from_response(
|
|
108
|
+
value: &Value,
|
|
109
|
+
) -> Option<(u16, Vec<(String, String)>, String)> {
|
|
107
110
|
let Value::Object(obj) = value else {
|
|
108
111
|
return None;
|
|
109
112
|
};
|
|
110
113
|
let obj_ref = obj.borrow();
|
|
111
|
-
let file_val = obj_ref.get(
|
|
114
|
+
let file_val = obj_ref.strings.get("file")?;
|
|
112
115
|
let Value::String(file_path) = file_val else {
|
|
113
116
|
return None;
|
|
114
117
|
};
|
|
115
118
|
let file_path = file_path.to_string();
|
|
116
119
|
let status = obj_ref
|
|
117
|
-
.
|
|
120
|
+
.strings
|
|
121
|
+
.get("status")
|
|
118
122
|
.and_then(|v| match v {
|
|
119
123
|
Value::Number(n) => Some(*n as u16),
|
|
120
124
|
_ => None,
|
|
121
125
|
})
|
|
122
126
|
.unwrap_or(200);
|
|
123
127
|
let headers = obj_ref
|
|
124
|
-
.
|
|
128
|
+
.strings
|
|
129
|
+
.get("headers")
|
|
125
130
|
.and_then(|v| match v {
|
|
126
131
|
Value::Object(h) => Some(
|
|
127
132
|
h.borrow()
|
|
133
|
+
.strings
|
|
128
134
|
.iter()
|
|
129
135
|
.map(|(k, v)| (k.to_string(), v.to_string()))
|
|
130
136
|
.collect(),
|
|
@@ -68,3 +68,32 @@ pub fn run_file(
|
|
|
68
68
|
eval.run_timer_phase()?;
|
|
69
69
|
Ok(result)
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
#[cfg(test)]
|
|
73
|
+
mod global_scope_tests {
|
|
74
|
+
use super::*;
|
|
75
|
+
|
|
76
|
+
#[test]
|
|
77
|
+
fn symbol_global_loads() {
|
|
78
|
+
let mut e = Evaluator::new();
|
|
79
|
+
let program = tishlang_parser::parse("Symbol").expect("parse");
|
|
80
|
+
let r = e.eval_program(&program);
|
|
81
|
+
assert!(
|
|
82
|
+
r.is_ok(),
|
|
83
|
+
"expected Symbol global, got {:?}",
|
|
84
|
+
r.as_ref().err()
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#[test]
|
|
89
|
+
fn symbol_call_under_typeof_loads() {
|
|
90
|
+
let mut e = Evaluator::new();
|
|
91
|
+
let program = tishlang_parser::parse("typeof Symbol(\"z\")").expect("parse");
|
|
92
|
+
let r = e.eval_program(&program);
|
|
93
|
+
assert!(
|
|
94
|
+
r.is_ok(),
|
|
95
|
+
"expected Symbol global for typeof Symbol(\"z\"), got {:?}",
|
|
96
|
+
r.as_ref().err()
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|