@tishlang/tish 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/Cargo.toml +1 -0
  2. package/bin/tish +0 -0
  3. package/crates/js_to_tish/src/error.rs +2 -8
  4. package/crates/js_to_tish/src/transform/expr.rs +101 -130
  5. package/crates/js_to_tish/src/transform/stmt.rs +25 -22
  6. package/crates/tish/Cargo.toml +1 -1
  7. package/crates/tish/src/cli_help.rs +76 -29
  8. package/crates/tish/src/main.rs +85 -54
  9. package/crates/tish/tests/cargo_example_compile.rs +3 -1
  10. package/crates/tish/tests/integration_test.rs +197 -47
  11. package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
  12. package/crates/tish/tests/shortcircuit.rs +19 -4
  13. package/crates/tish_ast/src/ast.rs +12 -14
  14. package/crates/tish_build_utils/src/lib.rs +31 -6
  15. package/crates/tish_builtins/src/array.rs +52 -21
  16. package/crates/tish_builtins/src/construct.rs +2 -8
  17. package/crates/tish_builtins/src/globals.rs +30 -15
  18. package/crates/tish_builtins/src/lib.rs +5 -5
  19. package/crates/tish_builtins/src/math.rs +5 -3
  20. package/crates/tish_builtins/src/string.rs +71 -19
  21. package/crates/tish_bytecode/src/chunk.rs +0 -1
  22. package/crates/tish_bytecode/src/compiler.rs +164 -60
  23. package/crates/tish_bytecode/src/opcode.rs +13 -4
  24. package/crates/tish_bytecode/src/peephole.rs +2 -2
  25. package/crates/tish_compile/src/codegen.rs +921 -299
  26. package/crates/tish_compile/src/infer.rs +69 -19
  27. package/crates/tish_compile/src/lib.rs +15 -5
  28. package/crates/tish_compile/src/resolve.rs +112 -69
  29. package/crates/tish_compile/src/types.rs +10 -14
  30. package/crates/tish_compile_js/src/codegen.rs +34 -13
  31. package/crates/tish_compile_js/src/tests_jsx.rs +30 -6
  32. package/crates/tish_compiler_wasm/src/lib.rs +16 -13
  33. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +39 -48
  34. package/crates/tish_core/src/json.rs +5 -3
  35. package/crates/tish_core/src/lib.rs +1 -1
  36. package/crates/tish_core/src/uri.rs +9 -6
  37. package/crates/tish_core/src/value.rs +92 -28
  38. package/crates/tish_cranelift/src/link.rs +6 -9
  39. package/crates/tish_cranelift/src/lower.rs +14 -8
  40. package/crates/tish_eval/src/eval.rs +389 -142
  41. package/crates/tish_eval/src/lib.rs +10 -6
  42. package/crates/tish_eval/src/natives.rs +95 -38
  43. package/crates/tish_eval/src/promise.rs +14 -8
  44. package/crates/tish_eval/src/timers.rs +28 -19
  45. package/crates/tish_eval/src/value.rs +10 -3
  46. package/crates/tish_fmt/src/lib.rs +29 -13
  47. package/crates/tish_lexer/src/lib.rs +217 -63
  48. package/crates/tish_lexer/src/token.rs +6 -6
  49. package/crates/tish_llvm/src/lib.rs +15 -8
  50. package/crates/tish_lsp/src/main.rs +41 -43
  51. package/crates/tish_native/src/build.rs +1 -6
  52. package/crates/tish_native/src/lib.rs +48 -19
  53. package/crates/tish_opt/src/lib.rs +67 -50
  54. package/crates/tish_parser/src/lib.rs +36 -11
  55. package/crates/tish_parser/src/parser.rs +172 -87
  56. package/crates/tish_runtime/src/http.rs +15 -6
  57. package/crates/tish_runtime/src/http_fetch.rs +24 -14
  58. package/crates/tish_runtime/src/lib.rs +224 -168
  59. package/crates/tish_runtime/src/promise.rs +1 -5
  60. package/crates/tish_runtime/src/ws.rs +45 -20
  61. package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
  62. package/crates/tish_ui/src/jsx.rs +41 -22
  63. package/crates/tish_ui/src/lib.rs +2 -2
  64. package/crates/tish_vm/src/vm.rs +309 -112
  65. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +8 -3
  66. package/crates/tish_wasm/src/lib.rs +38 -28
  67. package/crates/tishlang_cargo_bindgen/Cargo.toml +25 -0
  68. package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
  69. package/crates/tishlang_cargo_bindgen/src/discover.rs +52 -0
  70. package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
  71. package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
  72. package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
  73. package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -0
  74. package/package.json +1 -1
  75. package/platform/darwin-arm64/tish +0 -0
  76. package/platform/darwin-x64/tish +0 -0
  77. package/platform/linux-arm64/tish +0 -0
  78. package/platform/linux-x64/tish +0 -0
  79. package/platform/win32-x64/tish.exe +0 -0
@@ -8,9 +8,9 @@ use std::sync::Arc;
8
8
  use tishlang_ast::{BinOp, UnaryOp};
9
9
  use tishlang_builtins::array as arr_builtins;
10
10
  use tishlang_builtins::construct as construct_builtin;
11
- use tishlang_builtins::string as str_builtins;
12
11
  use tishlang_builtins::globals as globals_builtins;
13
12
  use tishlang_builtins::math as math_builtins;
13
+ use tishlang_builtins::string as str_builtins;
14
14
  use tishlang_bytecode::{u8_to_binop, u8_to_unaryop, Chunk, Constant, Opcode, NO_REST_PARAM};
15
15
  use tishlang_core::{ObjectMap, Value};
16
16
 
@@ -51,12 +51,24 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
51
51
  #[cfg(feature = "fs")]
52
52
  if spec == "tish:fs" && cap_allows(enabled, "fs") {
53
53
  return match export_name {
54
- "readFile" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::read_file(args)))),
55
- "writeFile" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::write_file(args)))),
56
- "fileExists" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::file_exists(args)))),
57
- "isDir" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::is_dir(args)))),
58
- "readDir" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::read_dir(args)))),
59
- "mkdir" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::mkdir(args)))),
54
+ "readFile" => Some(Value::Function(Rc::new(|args: &[Value]| {
55
+ tishlang_runtime::read_file(args)
56
+ }))),
57
+ "writeFile" => Some(Value::Function(Rc::new(|args: &[Value]| {
58
+ tishlang_runtime::write_file(args)
59
+ }))),
60
+ "fileExists" => Some(Value::Function(Rc::new(|args: &[Value]| {
61
+ tishlang_runtime::file_exists(args)
62
+ }))),
63
+ "isDir" => Some(Value::Function(Rc::new(|args: &[Value]| {
64
+ tishlang_runtime::is_dir(args)
65
+ }))),
66
+ "readDir" => Some(Value::Function(Rc::new(|args: &[Value]| {
67
+ tishlang_runtime::read_dir(args)
68
+ }))),
69
+ "mkdir" => Some(Value::Function(Rc::new(|args: &[Value]| {
70
+ tishlang_runtime::mkdir(args)
71
+ }))),
60
72
  _ => None,
61
73
  };
62
74
  }
@@ -87,9 +99,15 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
87
99
  #[cfg(feature = "process")]
88
100
  if spec == "tish:process" && cap_allows(enabled, "process") {
89
101
  return match export_name {
90
- "exit" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_exit(args)))),
91
- "cwd" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_cwd(args)))),
92
- "exec" => Some(Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_exec(args)))),
102
+ "exit" => Some(Value::Function(Rc::new(|args: &[Value]| {
103
+ tishlang_runtime::process_exit(args)
104
+ }))),
105
+ "cwd" => Some(Value::Function(Rc::new(|args: &[Value]| {
106
+ tishlang_runtime::process_cwd(args)
107
+ }))),
108
+ "exec" => Some(Value::Function(Rc::new(|args: &[Value]| {
109
+ tishlang_runtime::process_exec(args)
110
+ }))),
93
111
  "argv" => Some(Value::Array(Rc::new(RefCell::new(
94
112
  std::env::args().map(|s| Value::String(s.into())).collect(),
95
113
  )))),
@@ -100,9 +118,24 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
100
118
  )))),
101
119
  "process" => {
102
120
  let mut m = ObjectMap::default();
103
- m.insert("exit".into(), Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_exit(args))));
104
- m.insert("cwd".into(), Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_cwd(args))));
105
- m.insert("exec".into(), Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_exec(args))));
121
+ m.insert(
122
+ "exit".into(),
123
+ Value::Function(Rc::new(|args: &[Value]| {
124
+ tishlang_runtime::process_exit(args)
125
+ })),
126
+ );
127
+ m.insert(
128
+ "cwd".into(),
129
+ Value::Function(Rc::new(|args: &[Value]| {
130
+ tishlang_runtime::process_cwd(args)
131
+ })),
132
+ );
133
+ m.insert(
134
+ "exec".into(),
135
+ Value::Function(Rc::new(|args: &[Value]| {
136
+ tishlang_runtime::process_exec(args)
137
+ })),
138
+ );
106
139
  m.insert(
107
140
  "argv".into(),
108
141
  Value::Array(Rc::new(RefCell::new(
@@ -134,7 +167,10 @@ fn get_builtin_export(enabled: &HashSet<String>, spec: &str, export_name: &str)
134
167
  "wsSend" => Some(Value::Function(Rc::new(|args: &[Value]| {
135
168
  Value::Bool(tishlang_runtime::ws_send_native(
136
169
  args.first().unwrap_or(&Value::Null),
137
- &args.get(1).map(|v| v.to_display_string()).unwrap_or_default(),
170
+ &args
171
+ .get(1)
172
+ .map(|v| v.to_display_string())
173
+ .unwrap_or_default(),
138
174
  ))
139
175
  }))),
140
176
  "wsBroadcast" => Some(Value::Function(Rc::new(|args: &[Value]| {
@@ -183,7 +219,8 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
183
219
  console.insert(
184
220
  "debug".into(),
185
221
  Value::Function(Rc::new(|args: &[Value]| {
186
- let s = tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
222
+ let s =
223
+ tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
187
224
  vm_log(&s);
188
225
  Value::Null
189
226
  })),
@@ -191,7 +228,8 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
191
228
  console.insert(
192
229
  "log".into(),
193
230
  Value::Function(Rc::new(|args: &[Value]| {
194
- let s = tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
231
+ let s =
232
+ tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
195
233
  vm_log(&s);
196
234
  Value::Null
197
235
  })),
@@ -199,7 +237,8 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
199
237
  console.insert(
200
238
  "info".into(),
201
239
  Value::Function(Rc::new(|args: &[Value]| {
202
- let s = tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
240
+ let s =
241
+ tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
203
242
  vm_log(&s);
204
243
  Value::Null
205
244
  })),
@@ -207,7 +246,8 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
207
246
  console.insert(
208
247
  "warn".into(),
209
248
  Value::Function(Rc::new(|args: &[Value]| {
210
- let s = tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
249
+ let s =
250
+ tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
211
251
  vm_log_err(&s);
212
252
  Value::Null
213
253
  })),
@@ -215,12 +255,16 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
215
255
  console.insert(
216
256
  "error".into(),
217
257
  Value::Function(Rc::new(|args: &[Value]| {
218
- let s = tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
258
+ let s =
259
+ tishlang_core::format_values_for_console(args, tishlang_core::use_console_colors());
219
260
  vm_log_err(&s);
220
261
  Value::Null
221
262
  })),
222
263
  );
223
- g.insert("console".into(), Value::Object(Rc::new(RefCell::new(console))));
264
+ g.insert(
265
+ "console".into(),
266
+ Value::Object(Rc::new(RefCell::new(console))),
267
+ );
224
268
 
225
269
  let mut math = ObjectMap::default();
226
270
  math.insert(
@@ -276,14 +320,38 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
276
320
  Value::Number(nums.into_iter().fold(f64::NAN, |a, b| a.max(b)))
277
321
  })),
278
322
  );
279
- math.insert("pow".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::pow(args))));
280
- math.insert("sin".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::sin(args))));
281
- math.insert("cos".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::cos(args))));
282
- math.insert("tan".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::tan(args))));
283
- math.insert("log".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::log(args))));
284
- math.insert("exp".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::exp(args))));
285
- math.insert("sign".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::sign(args))));
286
- math.insert("trunc".into(), Value::Function(Rc::new(|args: &[Value]| math_builtins::trunc(args))));
323
+ math.insert(
324
+ "pow".into(),
325
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::pow(args))),
326
+ );
327
+ math.insert(
328
+ "sin".into(),
329
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::sin(args))),
330
+ );
331
+ math.insert(
332
+ "cos".into(),
333
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::cos(args))),
334
+ );
335
+ math.insert(
336
+ "tan".into(),
337
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::tan(args))),
338
+ );
339
+ math.insert(
340
+ "log".into(),
341
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::log(args))),
342
+ );
343
+ math.insert(
344
+ "exp".into(),
345
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::exp(args))),
346
+ );
347
+ math.insert(
348
+ "sign".into(),
349
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::sign(args))),
350
+ );
351
+ math.insert(
352
+ "trunc".into(),
353
+ Value::Function(Rc::new(|args: &[Value]| math_builtins::trunc(args))),
354
+ );
287
355
  math.insert("PI".into(), Value::Number(std::f64::consts::PI));
288
356
  math.insert("E".into(), Value::Number(std::f64::consts::E));
289
357
  g.insert("Math".into(), Value::Object(Rc::new(RefCell::new(math))));
@@ -292,7 +360,10 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
292
360
  json.insert(
293
361
  "parse".into(),
294
362
  Value::Function(Rc::new(|args: &[Value]| {
295
- let s = args.first().map(|v| v.to_display_string()).unwrap_or_default();
363
+ let s = args
364
+ .first()
365
+ .map(|v| v.to_display_string())
366
+ .unwrap_or_default();
296
367
  tishlang_core::json_parse(&s).unwrap_or(Value::Null)
297
368
  })),
298
369
  );
@@ -305,13 +376,36 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
305
376
  );
306
377
  g.insert("JSON".into(), Value::Object(Rc::new(RefCell::new(json))));
307
378
 
308
- g.insert("parseInt".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::parse_int(args))));
309
- g.insert("parseFloat".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::parse_float(args))));
310
- g.insert("encodeURI".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::encode_uri(args))));
311
- g.insert("decodeURI".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::decode_uri(args))));
312
- g.insert("Boolean".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::boolean(args))));
313
- g.insert("isFinite".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::is_finite(args))));
314
- g.insert("isNaN".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::is_nan(args))));
379
+ g.insert(
380
+ "parseInt".into(),
381
+ Value::Function(Rc::new(|args: &[Value]| globals_builtins::parse_int(args))),
382
+ );
383
+ g.insert(
384
+ "parseFloat".into(),
385
+ Value::Function(Rc::new(|args: &[Value]| {
386
+ globals_builtins::parse_float(args)
387
+ })),
388
+ );
389
+ g.insert(
390
+ "encodeURI".into(),
391
+ Value::Function(Rc::new(|args: &[Value]| globals_builtins::encode_uri(args))),
392
+ );
393
+ g.insert(
394
+ "decodeURI".into(),
395
+ Value::Function(Rc::new(|args: &[Value]| globals_builtins::decode_uri(args))),
396
+ );
397
+ g.insert(
398
+ "Boolean".into(),
399
+ Value::Function(Rc::new(|args: &[Value]| globals_builtins::boolean(args))),
400
+ );
401
+ g.insert(
402
+ "isFinite".into(),
403
+ Value::Function(Rc::new(|args: &[Value]| globals_builtins::is_finite(args))),
404
+ );
405
+ g.insert(
406
+ "isNaN".into(),
407
+ Value::Function(Rc::new(|args: &[Value]| globals_builtins::is_nan(args))),
408
+ );
315
409
  g.insert("Infinity".into(), Value::Number(f64::INFINITY));
316
410
  g.insert("NaN".into(), Value::Number(f64::NAN));
317
411
  g.insert(
@@ -349,31 +443,68 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
349
443
  let mut object_methods = ObjectMap::default();
350
444
  object_methods.insert(
351
445
  "assign".into(),
352
- Value::Function(Rc::new(|args: &[Value]| globals_builtins::object_assign(args))),
446
+ Value::Function(Rc::new(|args: &[Value]| {
447
+ globals_builtins::object_assign(args)
448
+ })),
353
449
  );
354
450
  object_methods.insert(
355
451
  "fromEntries".into(),
356
- Value::Function(Rc::new(|args: &[Value]| globals_builtins::object_from_entries(args))),
452
+ Value::Function(Rc::new(|args: &[Value]| {
453
+ globals_builtins::object_from_entries(args)
454
+ })),
455
+ );
456
+ object_methods.insert(
457
+ "keys".into(),
458
+ Value::Function(Rc::new(|args: &[Value]| {
459
+ globals_builtins::object_keys(args)
460
+ })),
461
+ );
462
+ object_methods.insert(
463
+ "values".into(),
464
+ Value::Function(Rc::new(|args: &[Value]| {
465
+ globals_builtins::object_values(args)
466
+ })),
467
+ );
468
+ object_methods.insert(
469
+ "entries".into(),
470
+ Value::Function(Rc::new(|args: &[Value]| {
471
+ globals_builtins::object_entries(args)
472
+ })),
473
+ );
474
+ g.insert(
475
+ "Object".into(),
476
+ Value::Object(Rc::new(RefCell::new(object_methods))),
357
477
  );
358
- object_methods.insert("keys".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::object_keys(args))));
359
- object_methods.insert("values".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::object_values(args))));
360
- object_methods.insert("entries".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::object_entries(args))));
361
- g.insert("Object".into(), Value::Object(Rc::new(RefCell::new(object_methods))));
362
478
 
363
479
  // Array.isArray
364
480
  let mut array_static = ObjectMap::default();
365
481
  array_static.insert(
366
482
  "isArray".into(),
367
- Value::Function(Rc::new(|args: &[Value]| globals_builtins::array_is_array(args))),
483
+ Value::Function(Rc::new(|args: &[Value]| {
484
+ globals_builtins::array_is_array(args)
485
+ })),
486
+ );
487
+ g.insert(
488
+ "Array".into(),
489
+ Value::Object(Rc::new(RefCell::new(array_static))),
368
490
  );
369
- g.insert("Array".into(), Value::Object(Rc::new(RefCell::new(array_static))));
370
491
 
371
492
  // String(value) as callable + String.fromCharCode
372
- let string_convert_fn = Value::Function(Rc::new(|args: &[Value]| globals_builtins::string_convert(args)));
493
+ let string_convert_fn = Value::Function(Rc::new(|args: &[Value]| {
494
+ globals_builtins::string_convert(args)
495
+ }));
373
496
  let mut string_static = ObjectMap::default();
374
- string_static.insert("fromCharCode".into(), Value::Function(Rc::new(|args: &[Value]| globals_builtins::string_from_char_code(args))));
497
+ string_static.insert(
498
+ "fromCharCode".into(),
499
+ Value::Function(Rc::new(|args: &[Value]| {
500
+ globals_builtins::string_from_char_code(args)
501
+ })),
502
+ );
375
503
  string_static.insert(Arc::from("__call"), string_convert_fn);
376
- g.insert("String".into(), Value::Object(Rc::new(RefCell::new(string_static))));
504
+ g.insert(
505
+ "String".into(),
506
+ Value::Object(Rc::new(RefCell::new(string_static))),
507
+ );
377
508
 
378
509
  // JSX / Lattish: stubs for bytecode VM when no DOM (e.g. console). Override via set_global in browser.
379
510
  g.insert(
@@ -405,22 +536,31 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
405
536
  );
406
537
  let mut document_obj = ObjectMap::default();
407
538
  document_obj.insert("body".into(), Value::Null);
408
- g.insert("document".into(), Value::Object(Rc::new(RefCell::new(document_obj))));
539
+ g.insert(
540
+ "document".into(),
541
+ Value::Object(Rc::new(RefCell::new(document_obj))),
542
+ );
409
543
 
410
544
  #[cfg(feature = "process")]
411
545
  if cap_allows(enabled, "process") {
412
546
  let mut process_obj = ObjectMap::default();
413
547
  process_obj.insert(
414
548
  "exit".into(),
415
- Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_exit(args))),
549
+ Value::Function(Rc::new(|args: &[Value]| {
550
+ tishlang_runtime::process_exit(args)
551
+ })),
416
552
  );
417
553
  process_obj.insert(
418
554
  "cwd".into(),
419
- Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_cwd(args))),
555
+ Value::Function(Rc::new(|args: &[Value]| {
556
+ tishlang_runtime::process_cwd(args)
557
+ })),
420
558
  );
421
559
  process_obj.insert(
422
560
  "exec".into(),
423
- Value::Function(Rc::new(|args: &[Value]| tishlang_runtime::process_exec(args))),
561
+ Value::Function(Rc::new(|args: &[Value]| {
562
+ tishlang_runtime::process_exec(args)
563
+ })),
424
564
  );
425
565
  process_obj.insert(
426
566
  "argv".into(),
@@ -436,7 +576,10 @@ fn init_globals(enabled: &HashSet<String>) -> ObjectMap {
436
576
  .collect(),
437
577
  ))),
438
578
  );
439
- g.insert("process".into(), Value::Object(Rc::new(RefCell::new(process_obj))));
579
+ g.insert(
580
+ "process".into(),
581
+ Value::Object(Rc::new(RefCell::new(process_obj))),
582
+ );
440
583
  }
441
584
 
442
585
  #[cfg(feature = "http")]
@@ -511,7 +654,11 @@ impl Vm {
511
654
 
512
655
  /// Names of all globals (for REPL bare-word tab completion).
513
656
  pub fn global_names(&self) -> Vec<String> {
514
- self.globals.borrow().keys().map(|k| k.as_ref().to_string()).collect()
657
+ self.globals
658
+ .borrow()
659
+ .keys()
660
+ .map(|k| k.as_ref().to_string())
661
+ .collect()
515
662
  }
516
663
 
517
664
  fn read_u16(code: &[u8], ip: &mut usize) -> u16 {
@@ -663,9 +810,7 @@ impl Vm {
663
810
  } else if self.scope.contains_key(name.as_ref()) {
664
811
  self.scope.insert(Arc::clone(name), v);
665
812
  } else if self.globals.borrow().contains_key(name.as_ref()) {
666
- self.globals
667
- .borrow_mut()
668
- .insert(Arc::clone(name), v);
813
+ self.globals.borrow_mut().insert(Arc::clone(name), v);
669
814
  } else {
670
815
  // New variable: at top level (no enclosing) store in globals so REPL persists across lines
671
816
  if self.enclosing.is_none() {
@@ -716,9 +861,9 @@ impl Vm {
716
861
  block_undo_stack.push(Vec::new());
717
862
  }
718
863
  Opcode::ExitBlock => {
719
- let frame = block_undo_stack.pop().ok_or_else(|| {
720
- "ExitBlock without matching EnterBlock".to_string()
721
- })?;
864
+ let frame = block_undo_stack
865
+ .pop()
866
+ .ok_or_else(|| "ExitBlock without matching EnterBlock".to_string())?;
722
867
  for (name, old) in frame.into_iter().rev() {
723
868
  let mut ls = local_scope.borrow_mut();
724
869
  match old {
@@ -753,17 +898,19 @@ impl Vm {
753
898
  .stack
754
899
  .pop()
755
900
  .ok_or_else(|| "Stack underflow".to_string())?;
756
- self.globals
757
- .borrow_mut()
758
- .insert(Arc::clone(name), v);
901
+ self.globals.borrow_mut().insert(Arc::clone(name), v);
759
902
  }
760
903
  Opcode::Pop => {
761
- self.stack.pop().ok_or_else(|| "Stack underflow".to_string())?;
904
+ self.stack
905
+ .pop()
906
+ .ok_or_else(|| "Stack underflow".to_string())?;
762
907
  }
763
908
  Opcode::PopN => {
764
909
  let n = Self::read_u16(code, &mut ip) as usize;
765
910
  for _ in 0..n {
766
- self.stack.pop().ok_or_else(|| "Stack underflow".to_string())?;
911
+ self.stack
912
+ .pop()
913
+ .ok_or_else(|| "Stack underflow".to_string())?;
767
914
  }
768
915
  }
769
916
  Opcode::Dup => {
@@ -792,7 +939,9 @@ impl Vm {
792
939
  let f = match &callee {
793
940
  Value::Function(f) => Rc::clone(f),
794
941
  Value::Object(o) => {
795
- if let Some(Value::Function(call_fn)) = o.borrow().get(&Arc::from("__call")) {
942
+ if let Some(Value::Function(call_fn)) =
943
+ o.borrow().get(&Arc::from("__call"))
944
+ {
796
945
  Rc::clone(call_fn)
797
946
  } else {
798
947
  return Err(format!(
@@ -802,10 +951,7 @@ impl Vm {
802
951
  }
803
952
  }
804
953
  _ => {
805
- return Err(format!(
806
- "Call of non-function: {}",
807
- callee.type_name()
808
- ));
954
+ return Err(format!("Call of non-function: {}", callee.type_name()));
809
955
  }
810
956
  };
811
957
  let result = f(&args);
@@ -832,7 +978,9 @@ impl Vm {
832
978
  let f = match &callee {
833
979
  Value::Function(f) => Rc::clone(f),
834
980
  Value::Object(o) => {
835
- if let Some(Value::Function(call_fn)) = o.borrow().get(&Arc::from("__call")) {
981
+ if let Some(Value::Function(call_fn)) =
982
+ o.borrow().get(&Arc::from("__call"))
983
+ {
836
984
  Rc::clone(call_fn)
837
985
  } else {
838
986
  return Err(format!(
@@ -842,10 +990,7 @@ impl Vm {
842
990
  }
843
991
  }
844
992
  _ => {
845
- return Err(format!(
846
- "Call of non-function: {}",
847
- callee.type_name()
848
- ));
993
+ return Err(format!("Call of non-function: {}", callee.type_name()));
849
994
  }
850
995
  };
851
996
  let result = f(&args);
@@ -922,8 +1067,8 @@ impl Vm {
922
1067
  .stack
923
1068
  .pop()
924
1069
  .ok_or_else(|| "Stack underflow".to_string())?;
925
- let op = u8_to_binop(op_u8)
926
- .ok_or_else(|| format!("Unknown binop: {}", op_u8))?;
1070
+ let op =
1071
+ u8_to_binop(op_u8).ok_or_else(|| format!("Unknown binop: {}", op_u8))?;
927
1072
  let result = eval_binop(op, &l, &r)?;
928
1073
  self.stack.push(result);
929
1074
  }
@@ -1023,8 +1168,7 @@ impl Vm {
1023
1168
  );
1024
1169
  }
1025
1170
  elems.reverse();
1026
- self.stack
1027
- .push(Value::Array(Rc::new(RefCell::new(elems))));
1171
+ self.stack.push(Value::Array(Rc::new(RefCell::new(elems))));
1028
1172
  }
1029
1173
  Opcode::NewObject => {
1030
1174
  let n = Self::read_u16(code, &mut ip) as usize;
@@ -1041,8 +1185,7 @@ impl Vm {
1041
1185
  let key = key_val.to_display_string().into();
1042
1186
  map.insert(key, val);
1043
1187
  }
1044
- self.stack
1045
- .push(Value::Object(Rc::new(RefCell::new(map))));
1188
+ self.stack.push(Value::Object(Rc::new(RefCell::new(map))));
1046
1189
  }
1047
1190
  Opcode::EnterTry => {
1048
1191
  let offset = Self::read_u16(code, &mut ip) as usize;
@@ -1159,9 +1302,7 @@ impl Vm {
1159
1302
  .pop()
1160
1303
  .ok_or_else(|| "Stack underflow".to_string())?;
1161
1304
  let result = match &arr {
1162
- Value::Array(a) => {
1163
- Value::Array(Rc::new(RefCell::new(a.borrow().clone())))
1164
- }
1305
+ Value::Array(a) => Value::Array(Rc::new(RefCell::new(a.borrow().clone()))),
1165
1306
  _ => Value::Null,
1166
1307
  };
1167
1308
  self.stack.push(result);
@@ -1187,8 +1328,16 @@ impl Vm {
1187
1328
  let mapped: Vec<Value> = arr_borrow
1188
1329
  .iter()
1189
1330
  .map(|v| {
1190
- let l: Value = if param_left { (*v).clone() } else { const_val.clone() };
1191
- let r: Value = if param_left { const_val.clone() } else { (*v).clone() };
1331
+ let l: Value = if param_left {
1332
+ (*v).clone()
1333
+ } else {
1334
+ const_val.clone()
1335
+ };
1336
+ let r: Value = if param_left {
1337
+ const_val.clone()
1338
+ } else {
1339
+ (*v).clone()
1340
+ };
1192
1341
  eval_binop(binop, &l, &r).unwrap_or(Value::Null)
1193
1342
  })
1194
1343
  .collect();
@@ -1204,8 +1353,9 @@ impl Vm {
1204
1353
  let const_idx = Self::read_u16(code, &mut ip);
1205
1354
  let param_left = code[ip] == 0; // 0 = param on left (x op const), 1 = param on right (const op x)
1206
1355
  ip += 1;
1207
- let binop = u8_to_binop(binop_u8)
1208
- .ok_or_else(|| format!("Unknown binop in ArrayFilterBinOp: {}", binop_u8))?;
1356
+ let binop = u8_to_binop(binop_u8).ok_or_else(|| {
1357
+ format!("Unknown binop in ArrayFilterBinOp: {}", binop_u8)
1358
+ })?;
1209
1359
  let arr = self
1210
1360
  .stack
1211
1361
  .pop()
@@ -1219,8 +1369,16 @@ impl Vm {
1219
1369
  let filtered: Vec<Value> = arr_borrow
1220
1370
  .iter()
1221
1371
  .filter(|v| {
1222
- let l: Value = if param_left { (*v).clone() } else { const_val.clone() };
1223
- let r: Value = if param_left { const_val.clone() } else { (*v).clone() };
1372
+ let l: Value = if param_left {
1373
+ (*v).clone()
1374
+ } else {
1375
+ const_val.clone()
1376
+ };
1377
+ let r: Value = if param_left {
1378
+ const_val.clone()
1379
+ } else {
1380
+ (*v).clone()
1381
+ };
1224
1382
  let b = eval_binop(binop, &l, &r).unwrap_or(Value::Null);
1225
1383
  b.is_truthy()
1226
1384
  })
@@ -1250,7 +1408,10 @@ impl Vm {
1250
1408
  let spec = match constants.get(spec_idx as usize) {
1251
1409
  Some(Constant::String(s)) => s.as_ref(),
1252
1410
  _ => {
1253
- return Err("LoadNativeExport: spec constant out of bounds or not string".to_string());
1411
+ return Err(
1412
+ "LoadNativeExport: spec constant out of bounds or not string"
1413
+ .to_string(),
1414
+ );
1254
1415
  }
1255
1416
  };
1256
1417
  let export_name = match constants.get(export_idx as usize) {
@@ -1400,33 +1561,50 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
1400
1561
  match obj {
1401
1562
  Value::Object(m) => {
1402
1563
  let map = m.borrow();
1403
- map.get(key.as_ref()).cloned().ok_or_else(|| {
1404
- format!("Property '{}' not found", key)
1405
- })
1564
+ map.get(key.as_ref())
1565
+ .cloned()
1566
+ .ok_or_else(|| format!("Property '{}' not found", key))
1406
1567
  }
1407
1568
  Value::Array(a) => {
1408
1569
  let key_s = key.as_ref();
1409
1570
  if let Ok(idx) = key_s.parse::<usize>() {
1410
1571
  let arr = a.borrow();
1411
- return arr.get(idx).cloned().ok_or_else(|| "Index out of bounds".to_string());
1572
+ return arr
1573
+ .get(idx)
1574
+ .cloned()
1575
+ .ok_or_else(|| "Index out of bounds".to_string());
1412
1576
  }
1413
1577
  if key_s == "length" {
1414
1578
  return Ok(Value::Number(a.borrow().len() as f64));
1415
1579
  }
1416
1580
  let a_clone = Rc::clone(a);
1417
1581
  let method: ArrayMethodFn = match key_s {
1418
- "push" => Rc::new(move |args: &[Value]| arr_builtins::push(&Value::Array(Rc::clone(&a_clone)), args)),
1419
- "pop" => Rc::new(move |_args: &[Value]| arr_builtins::pop(&Value::Array(Rc::clone(&a_clone)))),
1420
- "shift" => Rc::new(move |_args: &[Value]| arr_builtins::shift(&Value::Array(Rc::clone(&a_clone)))),
1421
- "unshift" => Rc::new(move |args: &[Value]| arr_builtins::unshift(&Value::Array(Rc::clone(&a_clone)), args)),
1422
- "reverse" => Rc::new(move |_args: &[Value]| arr_builtins::reverse(&Value::Array(Rc::clone(&a_clone)))),
1423
- "shuffle" => Rc::new(move |_args: &[Value]| arr_builtins::shuffle(&Value::Array(Rc::clone(&a_clone)))),
1582
+ "push" => Rc::new(move |args: &[Value]| {
1583
+ arr_builtins::push(&Value::Array(Rc::clone(&a_clone)), args)
1584
+ }),
1585
+ "pop" => Rc::new(move |_args: &[Value]| {
1586
+ arr_builtins::pop(&Value::Array(Rc::clone(&a_clone)))
1587
+ }),
1588
+ "shift" => Rc::new(move |_args: &[Value]| {
1589
+ arr_builtins::shift(&Value::Array(Rc::clone(&a_clone)))
1590
+ }),
1591
+ "unshift" => Rc::new(move |args: &[Value]| {
1592
+ arr_builtins::unshift(&Value::Array(Rc::clone(&a_clone)), args)
1593
+ }),
1594
+ "reverse" => Rc::new(move |_args: &[Value]| {
1595
+ arr_builtins::reverse(&Value::Array(Rc::clone(&a_clone)))
1596
+ }),
1597
+ "shuffle" => Rc::new(move |_args: &[Value]| {
1598
+ arr_builtins::shuffle(&Value::Array(Rc::clone(&a_clone)))
1599
+ }),
1424
1600
  "slice" => Rc::new(move |args: &[Value]| {
1425
1601
  let start = args.first().unwrap_or(&Value::Null);
1426
1602
  let end = args.get(1).unwrap_or(&Value::Null);
1427
1603
  arr_builtins::slice(&Value::Array(Rc::clone(&a_clone)), start, end)
1428
1604
  }),
1429
- "concat" => Rc::new(move |args: &[Value]| arr_builtins::concat(&Value::Array(Rc::clone(&a_clone)), args)),
1605
+ "concat" => Rc::new(move |args: &[Value]| {
1606
+ arr_builtins::concat(&Value::Array(Rc::clone(&a_clone)), args)
1607
+ }),
1430
1608
  "join" => Rc::new(move |args: &[Value]| {
1431
1609
  let sep = args.first().unwrap_or(&Value::Null);
1432
1610
  arr_builtins::join(&Value::Array(Rc::clone(&a_clone)), sep)
@@ -1484,7 +1662,10 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
1484
1662
  "sort" => Rc::new(move |args: &[Value]| {
1485
1663
  let cmp = args.first();
1486
1664
  if let Some(Value::Function(_)) = cmp {
1487
- arr_builtins::sort_with_comparator(&Value::Array(Rc::clone(&a_clone)), cmp.unwrap())
1665
+ arr_builtins::sort_with_comparator(
1666
+ &Value::Array(Rc::clone(&a_clone)),
1667
+ cmp.unwrap(),
1668
+ )
1488
1669
  } else {
1489
1670
  arr_builtins::sort_default(&Value::Array(Rc::clone(&a_clone)))
1490
1671
  }
@@ -1493,7 +1674,12 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
1493
1674
  let start = args.first().unwrap_or(&Value::Null);
1494
1675
  let delete_count = args.get(1).map(|v| v as &Value);
1495
1676
  let items: Vec<Value> = args.get(2..).unwrap_or(&[]).to_vec();
1496
- arr_builtins::splice(&Value::Array(Rc::clone(&a_clone)), start, delete_count, &items)
1677
+ arr_builtins::splice(
1678
+ &Value::Array(Rc::clone(&a_clone)),
1679
+ start,
1680
+ delete_count,
1681
+ &items,
1682
+ )
1497
1683
  }),
1498
1684
  _ => return Err(format!("Property '{}' not found", key)),
1499
1685
  };
@@ -1519,10 +1705,7 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
1519
1705
  }),
1520
1706
  "lastIndexOf" => Rc::new(move |args: &[Value]| {
1521
1707
  let search = args.first().unwrap_or(&Value::Null);
1522
- let position = args
1523
- .get(1)
1524
- .cloned()
1525
- .unwrap_or(Value::Number(f64::INFINITY));
1708
+ let position = args.get(1).cloned().unwrap_or(Value::Number(f64::INFINITY));
1526
1709
  str_builtins::last_index_of(
1527
1710
  &Value::String(Arc::clone(&s_clone)),
1528
1711
  search,
@@ -1548,9 +1731,15 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
1548
1731
  let sep = args.first().unwrap_or(&Value::Null);
1549
1732
  str_builtins::split(&Value::String(Arc::clone(&s_clone)), sep)
1550
1733
  }),
1551
- "trim" => Rc::new(move |_args: &[Value]| str_builtins::trim(&Value::String(Arc::clone(&s_clone)))),
1552
- "toUpperCase" => Rc::new(move |_args: &[Value]| str_builtins::to_upper_case(&Value::String(Arc::clone(&s_clone)))),
1553
- "toLowerCase" => Rc::new(move |_args: &[Value]| str_builtins::to_lower_case(&Value::String(Arc::clone(&s_clone)))),
1734
+ "trim" => Rc::new(move |_args: &[Value]| {
1735
+ str_builtins::trim(&Value::String(Arc::clone(&s_clone)))
1736
+ }),
1737
+ "toUpperCase" => Rc::new(move |_args: &[Value]| {
1738
+ str_builtins::to_upper_case(&Value::String(Arc::clone(&s_clone)))
1739
+ }),
1740
+ "toLowerCase" => Rc::new(move |_args: &[Value]| {
1741
+ str_builtins::to_lower_case(&Value::String(Arc::clone(&s_clone)))
1742
+ }),
1554
1743
  "startsWith" => Rc::new(move |args: &[Value]| {
1555
1744
  let search = args.first().unwrap_or(&Value::Null);
1556
1745
  str_builtins::starts_with(&Value::String(Arc::clone(&s_clone)), search)
@@ -1567,7 +1756,11 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
1567
1756
  "replaceAll" => Rc::new(move |args: &[Value]| {
1568
1757
  let search = args.first().unwrap_or(&Value::Null);
1569
1758
  let replacement = args.get(1).unwrap_or(&Value::Null);
1570
- str_builtins::replace_all(&Value::String(Arc::clone(&s_clone)), search, replacement)
1759
+ str_builtins::replace_all(
1760
+ &Value::String(Arc::clone(&s_clone)),
1761
+ search,
1762
+ replacement,
1763
+ )
1571
1764
  }),
1572
1765
  "charAt" => Rc::new(move |args: &[Value]| {
1573
1766
  let idx = args.first().unwrap_or(&Value::Null);
@@ -1595,7 +1788,11 @@ fn get_member(obj: &Value, key: &Arc<str>) -> Result<Value, String> {
1595
1788
  };
1596
1789
  Ok(Value::Function(method))
1597
1790
  }
1598
- _ => Err(format!("Cannot read property '{}' of {}", key, obj.type_name())),
1791
+ _ => Err(format!(
1792
+ "Cannot read property '{}' of {}",
1793
+ key,
1794
+ obj.type_name()
1795
+ )),
1599
1796
  }
1600
1797
  }
1601
1798