@tishlang/tish-lsp 2.16.13 → 2.35.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-lsp +0 -0
- package/crates/js_to_tish/src/transform/expr.rs +12 -2
- package/crates/tish/tests/fixtures/fs_parity_callbacks.tish +22 -0
- package/crates/tish/tests/fixtures/fs_parity_promises.tish +21 -0
- package/crates/tish/tests/fixtures/fs_parity_sync.tish +20 -0
- package/crates/tish/tests/fs_parity.rs +103 -0
- package/crates/tish/tests/shortcircuit.rs +3 -3
- package/crates/tish_ast/src/ast.rs +77 -3
- package/crates/tish_builtins/Cargo.toml +1 -0
- package/crates/tish_builtins/src/array.rs +195 -16
- package/crates/tish_builtins/src/collections.rs +37 -2
- package/crates/tish_builtins/src/globals.rs +215 -25
- package/crates/tish_builtins/src/math.rs +65 -7
- package/crates/tish_builtins/src/number.rs +173 -0
- package/crates/tish_builtins/src/string.rs +168 -15
- package/crates/tish_bytecode/src/compiler.rs +56 -4
- package/crates/tish_bytecode/src/opcode.rs +4 -2
- package/crates/tish_compile/src/codegen.rs +513 -44
- package/crates/tish_compile/src/infer.rs +26 -11
- package/crates/tish_compile/src/resolve.rs +87 -10
- package/crates/tish_compile_js/src/codegen.rs +82 -24
- package/crates/tish_compile_js/src/tests_jsx.rs +27 -0
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +17 -2
- package/crates/tish_core/src/json.rs +5 -1
- package/crates/tish_core/src/lib.rs +48 -2
- package/crates/tish_core/src/uri.rs +45 -0
- package/crates/tish_core/src/value.rs +6 -0
- package/crates/tish_eval/Cargo.toml +2 -1
- package/crates/tish_eval/src/eval.rs +655 -27
- package/crates/tish_eval/src/natives.rs +264 -18
- package/crates/tish_eval/src/regex.rs +47 -1
- package/crates/tish_fmt/src/lib.rs +23 -4
- package/crates/tish_lsp/Cargo.toml +1 -1
- package/crates/tish_opt/src/lib.rs +20 -1
- package/crates/tish_parser/src/lib.rs +41 -0
- package/crates/tish_parser/src/parser.rs +180 -11
- package/crates/tish_resolve/src/lib.rs +66 -5
- package/crates/tish_runtime/Cargo.toml +5 -1
- package/crates/tish_runtime/src/fs_ext.rs +359 -0
- package/crates/tish_runtime/src/http_hyper.rs +41 -18
- package/crates/tish_runtime/src/lib.rs +128 -9
- package/crates/tish_ui/src/jsx.rs +18 -3
- package/crates/tish_vm/src/jit.rs +1 -1
- package/crates/tish_vm/src/vm.rs +270 -60
- package/package.json +1 -1
- package/platform/darwin-arm64/tish-lsp +0 -0
- package/platform/darwin-x64/tish-lsp +0 -0
- package/platform/linux-arm64/tish-lsp +0 -0
- package/platform/linux-x64/tish-lsp +0 -0
- package/platform/win32-x64/tish-lsp.exe +0 -0
|
@@ -118,18 +118,23 @@ pub use tishlang_builtins::array::{
|
|
|
118
118
|
find_last_index as array_find_last_index, flat as array_flat_impl, flat_map as array_flat_map,
|
|
119
119
|
for_each as array_for_each, includes as array_includes_impl, index_of as array_index_of_impl,
|
|
120
120
|
join as array_join_impl, map as array_map, pop as array_pop, push as array_push_impl,
|
|
121
|
-
fill as array_fill,
|
|
121
|
+
fill as array_fill, last_index_of as array_last_index_of, copy_within as array_copy_within,
|
|
122
|
+
reduce as array_reduce, reduce_right as array_reduce_right, reverse as array_reverse,
|
|
123
|
+
keys as array_keys, values as array_values, entries as array_entries, shift as array_shift,
|
|
122
124
|
shuffle as array_shuffle, slice as array_slice_impl, snapshot_values as array_snapshot_values,
|
|
123
125
|
as_f64_snapshot as array_as_f64_snapshot, some as array_some,
|
|
124
126
|
sort_by_keys as array_sort_by_keys, sort_default as array_sort_default,
|
|
125
127
|
sort_numeric_asc as array_sort_numeric_asc, sort_numeric_desc as array_sort_numeric_desc,
|
|
126
128
|
sort_with_comparator as array_sort_with_comparator, splice as array_splice_impl,
|
|
129
|
+
to_reversed as array_to_reversed, to_sorted as array_to_sorted,
|
|
130
|
+
to_spliced as array_to_spliced, with as array_with,
|
|
127
131
|
unshift as array_unshift_impl,
|
|
128
132
|
};
|
|
129
133
|
|
|
130
134
|
// Re-export string methods from tishlang_builtins
|
|
131
135
|
pub use tishlang_builtins::string::{
|
|
132
136
|
at as string_at_impl, char_at as string_char_at_impl, char_code_at as string_char_code_at_impl,
|
|
137
|
+
code_point_at as string_code_point_at,
|
|
133
138
|
ends_with as string_ends_with_impl, escape_html as string_escape_html_impl,
|
|
134
139
|
includes as string_includes_impl, index_of as string_index_of_impl,
|
|
135
140
|
last_index_of as string_last_index_of_impl, pad_end as string_pad_end_impl,
|
|
@@ -138,8 +143,9 @@ pub use tishlang_builtins::string::{
|
|
|
138
143
|
slice as string_slice_impl, split as string_split_impl, split_limit as string_split_limit_impl,
|
|
139
144
|
starts_with as string_starts_with_impl, substr as string_substr_impl,
|
|
140
145
|
substring as string_substring_impl,
|
|
141
|
-
|
|
142
|
-
trim as string_trim,
|
|
146
|
+
normalize as string_normalize, to_lower_case as string_to_lower_case,
|
|
147
|
+
to_upper_case as string_to_upper_case, trim as string_trim, trim_end as string_trim_end,
|
|
148
|
+
trim_start as string_trim_start,
|
|
143
149
|
};
|
|
144
150
|
|
|
145
151
|
// Wrapper functions to maintain API compatibility
|
|
@@ -149,8 +155,8 @@ pub fn array_push(arr: &Value, args: &[Value]) -> Value {
|
|
|
149
155
|
pub fn array_unshift(arr: &Value, args: &[Value]) -> Value {
|
|
150
156
|
array_unshift_impl(arr, args)
|
|
151
157
|
}
|
|
152
|
-
pub fn array_index_of(arr: &Value, search: &Value) -> Value {
|
|
153
|
-
array_index_of_impl(arr, search)
|
|
158
|
+
pub fn array_index_of(arr: &Value, search: &Value, from: Option<&Value>) -> Value {
|
|
159
|
+
array_index_of_impl(arr, search, from)
|
|
154
160
|
}
|
|
155
161
|
pub fn array_includes(arr: &Value, search: &Value, from: &Value) -> Value {
|
|
156
162
|
array_includes_impl(arr, search, Some(from))
|
|
@@ -217,11 +223,11 @@ pub fn string_split_limit(s: &Value, sep: &Value, limit: &Value) -> Value {
|
|
|
217
223
|
}
|
|
218
224
|
string_split_limit_impl(s, sep, max)
|
|
219
225
|
}
|
|
220
|
-
pub fn string_starts_with(s: &Value, search: &Value) -> Value {
|
|
221
|
-
string_starts_with_impl(s, search)
|
|
226
|
+
pub fn string_starts_with(s: &Value, search: &Value, position: Option<&Value>) -> Value {
|
|
227
|
+
string_starts_with_impl(s, search, position)
|
|
222
228
|
}
|
|
223
|
-
pub fn string_ends_with(s: &Value, search: &Value) -> Value {
|
|
224
|
-
string_ends_with_impl(s, search)
|
|
229
|
+
pub fn string_ends_with(s: &Value, search: &Value, end_position: Option<&Value>) -> Value {
|
|
230
|
+
string_ends_with_impl(s, search, end_position)
|
|
225
231
|
}
|
|
226
232
|
pub fn string_replace(s: &Value, search: &Value, replacement: &Value) -> Value {
|
|
227
233
|
#[cfg(feature = "regex")]
|
|
@@ -391,6 +397,12 @@ pub fn string_last_index_of(s: &Value, search: &Value, position: &Value) -> Valu
|
|
|
391
397
|
pub fn number_to_fixed(n: &Value, digits: &Value) -> Value {
|
|
392
398
|
tishlang_builtins::number::to_fixed(n, digits)
|
|
393
399
|
}
|
|
400
|
+
pub fn number_to_exponential(n: &Value, digits: &Value) -> Value {
|
|
401
|
+
tishlang_builtins::number::to_exponential(n, digits)
|
|
402
|
+
}
|
|
403
|
+
pub fn number_to_precision(n: &Value, precision: &Value) -> Value {
|
|
404
|
+
tishlang_builtins::number::to_precision(n, precision)
|
|
405
|
+
}
|
|
394
406
|
|
|
395
407
|
/// `.toString([radix])` for the compiled backend (issue #59). A number receiver uses the
|
|
396
408
|
/// shared radix formatter so it stays byte-identical with the VM / interpreter; any other
|
|
@@ -800,6 +812,15 @@ pub fn decode_uri(args: &[Value]) -> Value {
|
|
|
800
812
|
pub fn encode_uri(args: &[Value]) -> Value {
|
|
801
813
|
builtins_encode_uri(args)
|
|
802
814
|
}
|
|
815
|
+
pub fn encode_uri_component(args: &[Value]) -> Value {
|
|
816
|
+
tishlang_builtins::globals::encode_uri_component(args)
|
|
817
|
+
}
|
|
818
|
+
pub fn decode_uri_component(args: &[Value]) -> Value {
|
|
819
|
+
tishlang_builtins::globals::decode_uri_component(args)
|
|
820
|
+
}
|
|
821
|
+
pub fn structured_clone(args: &[Value]) -> Value {
|
|
822
|
+
tishlang_builtins::globals::structured_clone(args)
|
|
823
|
+
}
|
|
803
824
|
|
|
804
825
|
// Math functions - use tishlang_builtins::math
|
|
805
826
|
pub use tishlang_builtins::math::{
|
|
@@ -903,6 +924,14 @@ runtime_math_unary!(math_atanh, atanh);
|
|
|
903
924
|
runtime_math_unary!(math_cbrt, cbrt);
|
|
904
925
|
runtime_math_unary!(math_log2, log2);
|
|
905
926
|
runtime_math_unary!(math_log10, log10);
|
|
927
|
+
runtime_math_unary!(math_expm1, exp_m1);
|
|
928
|
+
runtime_math_unary!(math_log1p, ln_1p);
|
|
929
|
+
pub fn math_clz32(args: &[Value]) -> Value {
|
|
930
|
+
tishlang_builtins::math::clz32(args)
|
|
931
|
+
}
|
|
932
|
+
pub fn math_fround(args: &[Value]) -> Value {
|
|
933
|
+
tishlang_builtins::math::fround(args)
|
|
934
|
+
}
|
|
906
935
|
|
|
907
936
|
pub fn json_stringify(args: &[Value]) -> Value {
|
|
908
937
|
let v = args.first().cloned().unwrap_or(Value::Null);
|
|
@@ -921,6 +950,18 @@ pub fn json_parse(args: &[Value]) -> Value {
|
|
|
921
950
|
pub fn array_is_array(args: &[Value]) -> Value {
|
|
922
951
|
builtins_array_is_array(args)
|
|
923
952
|
}
|
|
953
|
+
pub fn array_of(args: &[Value]) -> Value {
|
|
954
|
+
tishlang_builtins::globals::array_of(args)
|
|
955
|
+
}
|
|
956
|
+
pub fn array_from(args: &[Value]) -> Value {
|
|
957
|
+
tishlang_builtins::globals::array_from(args)
|
|
958
|
+
}
|
|
959
|
+
pub fn object_is(args: &[Value]) -> Value {
|
|
960
|
+
tishlang_builtins::globals::object_is(args)
|
|
961
|
+
}
|
|
962
|
+
pub fn object_has_own(args: &[Value]) -> Value {
|
|
963
|
+
tishlang_builtins::globals::object_has_own(args)
|
|
964
|
+
}
|
|
924
965
|
|
|
925
966
|
pub fn string_from_char_code(args: &[Value]) -> Value {
|
|
926
967
|
builtins_string_from_char_code(args)
|
|
@@ -935,6 +976,18 @@ pub fn string_convert(args: &[Value]) -> Value {
|
|
|
935
976
|
pub fn number_convert(args: &[Value]) -> Value {
|
|
936
977
|
builtins_number_convert(args)
|
|
937
978
|
}
|
|
979
|
+
pub fn number_is_integer(args: &[Value]) -> Value {
|
|
980
|
+
tishlang_builtins::globals::number_is_integer(args)
|
|
981
|
+
}
|
|
982
|
+
pub fn number_is_safe_integer(args: &[Value]) -> Value {
|
|
983
|
+
tishlang_builtins::globals::number_is_safe_integer(args)
|
|
984
|
+
}
|
|
985
|
+
pub fn number_is_nan(args: &[Value]) -> Value {
|
|
986
|
+
tishlang_builtins::globals::number_is_nan(args)
|
|
987
|
+
}
|
|
988
|
+
pub fn number_is_finite(args: &[Value]) -> Value {
|
|
989
|
+
tishlang_builtins::globals::number_is_finite(args)
|
|
990
|
+
}
|
|
938
991
|
|
|
939
992
|
#[cfg(feature = "process")]
|
|
940
993
|
pub fn process_exit(args: &[Value]) -> Value {
|
|
@@ -1308,6 +1361,11 @@ pub fn get_index(obj: &Value, index: &Value) -> Value {
|
|
|
1308
1361
|
Value::Array(arr) => {
|
|
1309
1362
|
let idx = match index {
|
|
1310
1363
|
Value::Number(n) => *n as usize,
|
|
1364
|
+
// Canonical integer string key ("0","1",…) indexes the array (#432); other keys → Null.
|
|
1365
|
+
Value::String(s) => match tishlang_core::str_to_array_index(s) {
|
|
1366
|
+
Some(i) => i,
|
|
1367
|
+
None => return Value::Null,
|
|
1368
|
+
},
|
|
1311
1369
|
_ => return Value::Null,
|
|
1312
1370
|
};
|
|
1313
1371
|
arr.borrow().get(idx).cloned().unwrap_or(Value::Null)
|
|
@@ -1316,6 +1374,10 @@ pub fn get_index(obj: &Value, index: &Value) -> Value {
|
|
|
1316
1374
|
Value::NumberArray(arr) => {
|
|
1317
1375
|
let idx = match index {
|
|
1318
1376
|
Value::Number(n) => *n as usize,
|
|
1377
|
+
Value::String(s) => match tishlang_core::str_to_array_index(s) {
|
|
1378
|
+
Some(i) => i,
|
|
1379
|
+
None => return Value::Null,
|
|
1380
|
+
},
|
|
1319
1381
|
_ => return Value::Null,
|
|
1320
1382
|
};
|
|
1321
1383
|
arr.borrow().get(idx).copied().map(Value::Number).unwrap_or(Value::Null)
|
|
@@ -1416,6 +1478,11 @@ pub fn set_index(obj: &Value, idx: &Value, val: Value) -> Value {
|
|
|
1416
1478
|
Value::Array(arr) => {
|
|
1417
1479
|
let index = match idx {
|
|
1418
1480
|
Value::Number(n) => *n as usize,
|
|
1481
|
+
// Canonical integer string key → index (#432); a non-index string key is a no-op write.
|
|
1482
|
+
Value::String(s) => match tishlang_core::str_to_array_index(s) {
|
|
1483
|
+
Some(i) => i,
|
|
1484
|
+
None => return val,
|
|
1485
|
+
},
|
|
1419
1486
|
_ => panic!("Array index must be number"),
|
|
1420
1487
|
};
|
|
1421
1488
|
let mut arr_mut = arr.borrow_mut();
|
|
@@ -1432,6 +1499,11 @@ pub fn set_index(obj: &Value, idx: &Value, val: Value) -> Value {
|
|
|
1432
1499
|
Value::NumberArray(arr) => {
|
|
1433
1500
|
let index = match idx {
|
|
1434
1501
|
Value::Number(n) => *n as usize,
|
|
1502
|
+
// Canonical integer string key → index (#432); a non-index string key is a no-op write.
|
|
1503
|
+
Value::String(s) => match tishlang_core::str_to_array_index(s) {
|
|
1504
|
+
Some(i) => i,
|
|
1505
|
+
None => return val,
|
|
1506
|
+
},
|
|
1435
1507
|
_ => panic!("Array index must be number"),
|
|
1436
1508
|
};
|
|
1437
1509
|
let mut arr_mut = arr.borrow_mut();
|
|
@@ -1530,6 +1602,11 @@ mod timers;
|
|
|
1530
1602
|
#[cfg(any(feature = "http", feature = "promise"))]
|
|
1531
1603
|
mod promise;
|
|
1532
1604
|
|
|
1605
|
+
/// Node-compatible fs surface (sync + `fs/promises`). Referenced by the backends via
|
|
1606
|
+
/// `tishlang_runtime::fs_ext::*`. See issue #122.
|
|
1607
|
+
#[cfg(feature = "fs")]
|
|
1608
|
+
pub mod fs_ext;
|
|
1609
|
+
|
|
1533
1610
|
#[cfg(feature = "http")]
|
|
1534
1611
|
mod native_promise;
|
|
1535
1612
|
|
|
@@ -1830,6 +1907,48 @@ pub fn string_match_regex(s: &Value, regexp: &Value) -> Value {
|
|
|
1830
1907
|
}
|
|
1831
1908
|
}
|
|
1832
1909
|
|
|
1910
|
+
/// `String.prototype.matchAll(regexp)` — an ITERATOR over every match, each an exec-style match object
|
|
1911
|
+
/// (`{ "0", ...groups, index, input, groups }`). Per ECMA the regexp must be global, else a `TypeError`
|
|
1912
|
+
/// is parked; a non-RegExp argument is coerced to a global regex. Reuses `regexp_exec_impl` so the
|
|
1913
|
+
/// match objects are byte-identical to `exec`/`match`, then wraps them in the shared iterator.
|
|
1914
|
+
#[cfg(feature = "regex")]
|
|
1915
|
+
pub fn string_match_all_regex(s: &Value, regexp: &Value) -> Value {
|
|
1916
|
+
let input = match s {
|
|
1917
|
+
Value::String(s) => s.as_ref(),
|
|
1918
|
+
_ => return Value::Null,
|
|
1919
|
+
};
|
|
1920
|
+
let re_cell = match regexp {
|
|
1921
|
+
Value::RegExp(re) => re.clone(),
|
|
1922
|
+
other => {
|
|
1923
|
+
let pattern = other.to_display_string();
|
|
1924
|
+
match tishlang_core::TishRegExp::new(&pattern, "g") {
|
|
1925
|
+
Ok(re) => tishlang_core::VmRef::new(re),
|
|
1926
|
+
Err(_) => return Value::Null,
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
};
|
|
1930
|
+
if !re_cell.borrow().flags.global {
|
|
1931
|
+
tishlang_core::set_pending_throw(tishlang_core::type_error(
|
|
1932
|
+
"String.prototype.matchAll called with a non-global RegExp argument",
|
|
1933
|
+
));
|
|
1934
|
+
return Value::Null;
|
|
1935
|
+
}
|
|
1936
|
+
let mut results: Vec<Value> = Vec::new();
|
|
1937
|
+
{
|
|
1938
|
+
let mut re = re_cell.borrow_mut();
|
|
1939
|
+
re.last_index = 0;
|
|
1940
|
+
loop {
|
|
1941
|
+
let m = regexp_exec_impl(&mut re, input);
|
|
1942
|
+
if matches!(m, Value::Null) {
|
|
1943
|
+
break;
|
|
1944
|
+
}
|
|
1945
|
+
results.push(m);
|
|
1946
|
+
}
|
|
1947
|
+
re.last_index = 0;
|
|
1948
|
+
}
|
|
1949
|
+
tishlang_builtins::iterator::array_iterator(results)
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1833
1952
|
#[cfg(feature = "regex")]
|
|
1834
1953
|
fn string_replace_regex_or_callback(s: &Value, search: &Value, replacement: &Value) -> Value {
|
|
1835
1954
|
let input = match s {
|
|
@@ -188,7 +188,12 @@ fn collect_fun_decl_names_stmt(stmt: &Statement, names: &mut HashSet<String>) {
|
|
|
188
188
|
}
|
|
189
189
|
collect_fun_decl_names_stmt(body, names);
|
|
190
190
|
}
|
|
191
|
-
Statement::ForOf { iterable, body, .. }
|
|
191
|
+
Statement::ForOf { iterable, body, .. }
|
|
192
|
+
| Statement::ForIn {
|
|
193
|
+
object: iterable,
|
|
194
|
+
body,
|
|
195
|
+
..
|
|
196
|
+
} => {
|
|
192
197
|
collect_fun_decl_names_expr(iterable, names);
|
|
193
198
|
collect_fun_decl_names_stmt(body, names);
|
|
194
199
|
}
|
|
@@ -646,7 +651,12 @@ fn stmt_contains_jsx_fragment(stmt: &tishlang_ast::Statement) -> bool {
|
|
|
646
651
|
|| update.as_ref().is_some_and(expr_contains_jsx_fragment)
|
|
647
652
|
|| stmt_contains_jsx_fragment(body)
|
|
648
653
|
}
|
|
649
|
-
Statement::ForOf { iterable, body, .. }
|
|
654
|
+
Statement::ForOf { iterable, body, .. }
|
|
655
|
+
| Statement::ForIn {
|
|
656
|
+
object: iterable,
|
|
657
|
+
body,
|
|
658
|
+
..
|
|
659
|
+
} => {
|
|
650
660
|
expr_contains_jsx_fragment(iterable) || stmt_contains_jsx_fragment(body)
|
|
651
661
|
}
|
|
652
662
|
Statement::Switch {
|
|
@@ -827,7 +837,12 @@ fn stmt_contains_jsx(stmt: &tishlang_ast::Statement) -> bool {
|
|
|
827
837
|
|| update.as_ref().is_some_and(expr_contains_jsx)
|
|
828
838
|
|| stmt_contains_jsx(body)
|
|
829
839
|
}
|
|
830
|
-
Statement::ForOf { iterable, body, .. }
|
|
840
|
+
Statement::ForOf { iterable, body, .. }
|
|
841
|
+
| Statement::ForIn {
|
|
842
|
+
object: iterable,
|
|
843
|
+
body,
|
|
844
|
+
..
|
|
845
|
+
} => {
|
|
831
846
|
expr_contains_jsx(iterable) || stmt_contains_jsx(body)
|
|
832
847
|
}
|
|
833
848
|
Statement::Switch {
|
|
@@ -3634,7 +3634,7 @@ mod tests {
|
|
|
3634
3634
|
#[test]
|
|
3635
3635
|
fn osr_region_handles_branches() {
|
|
3636
3636
|
let chunk = top_chunk(
|
|
3637
|
-
"let s = 0.0\nlet i = 0.0\nwhile (i < 20.0) { if (i % 2.0
|
|
3637
|
+
"let s = 0.0\nlet i = 0.0\nwhile (i < 20.0) { if (i % 2.0 === 0.0) { s = s + i }; i = i + 1.0 }\n",
|
|
3638
3638
|
);
|
|
3639
3639
|
let (header, end) = first_region(&chunk);
|
|
3640
3640
|
let lf =
|