@tishlang/tish 2.12.0 → 2.16.13

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 (71) hide show
  1. package/Cargo.toml +3 -0
  2. package/bin/tish +0 -0
  3. package/crates/tish/Cargo.toml +1 -1
  4. package/crates/tish/tests/integration_test.rs +80 -0
  5. package/crates/tish_ast/src/ast.rs +10 -0
  6. package/crates/tish_builtins/src/array.rs +529 -56
  7. package/crates/tish_builtins/src/collections.rs +114 -40
  8. package/crates/tish_builtins/src/string.rs +95 -8
  9. package/crates/tish_bytecode/src/chunk.rs +7 -0
  10. package/crates/tish_bytecode/src/compiler.rs +560 -64
  11. package/crates/tish_bytecode/src/lib.rs +1 -1
  12. package/crates/tish_bytecode/src/opcode.rs +154 -2
  13. package/crates/tish_bytecode/src/serialize.rs +2 -0
  14. package/crates/tish_bytecode/tests/append_local_string_builder.rs +63 -0
  15. package/crates/tish_bytecode/tests/math_unary_intrinsic.rs +47 -0
  16. package/crates/tish_compile/src/codegen.rs +17736 -5269
  17. package/crates/tish_compile/src/infer.rs +1707 -190
  18. package/crates/tish_compile/src/lib.rs +29 -4
  19. package/crates/tish_compile/src/resolve.rs +66 -5
  20. package/crates/tish_compile/src/types.rs +224 -28
  21. package/crates/tish_compile/tests/dump_codegen.rs +21 -0
  22. package/crates/tish_compile/tests/perf_codegen_169_173.rs +8 -17
  23. package/crates/tish_compile/tests/perf_codegen_173_part3.rs +61 -0
  24. package/crates/tish_compile/tests/perf_codegen_174.rs +160 -0
  25. package/crates/tish_compile/tests/perf_codegen_175.rs +190 -0
  26. package/crates/tish_compile/tests/perf_codegen_176.rs +60 -0
  27. package/crates/tish_compile/tests/perf_codegen_177.rs +167 -0
  28. package/crates/tish_compile/tests/perf_codegen_178.rs +114 -0
  29. package/crates/tish_compile/tests/perf_codegen_178_rec.rs +124 -0
  30. package/crates/tish_compile/tests/perf_codegen_181.rs +36 -0
  31. package/crates/tish_compile/tests/perf_codegen_320.rs +211 -0
  32. package/crates/tish_compile/tests/perf_codegen_module_const_forof.rs +40 -0
  33. package/crates/tish_compile_js/src/codegen.rs +33 -0
  34. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +100 -2
  35. package/crates/tish_core/Cargo.toml +4 -0
  36. package/crates/tish_core/src/json.rs +104 -5
  37. package/crates/tish_core/src/lib.rs +174 -0
  38. package/crates/tish_core/src/shape.rs +4 -2
  39. package/crates/tish_core/src/value.rs +565 -35
  40. package/crates/tish_core/src/vmref.rs +14 -0
  41. package/crates/tish_eval/src/eval.rs +675 -76
  42. package/crates/tish_eval/src/natives.rs +19 -0
  43. package/crates/tish_eval/src/value.rs +76 -21
  44. package/crates/tish_ffi/src/lib.rs +11 -1
  45. package/crates/tish_ffi/tests/double_free.rs +35 -0
  46. package/crates/tish_fmt/src/lib.rs +75 -1
  47. package/crates/tish_lexer/src/lib.rs +76 -0
  48. package/crates/tish_lexer/src/token.rs +4 -0
  49. package/crates/tish_lint/src/lib.rs +126 -0
  50. package/crates/tish_lsp/README.md +2 -1
  51. package/crates/tish_lsp/src/main.rs +378 -28
  52. package/crates/tish_native/src/build.rs +41 -0
  53. package/crates/tish_parser/Cargo.toml +4 -0
  54. package/crates/tish_parser/src/lib.rs +27 -0
  55. package/crates/tish_parser/src/parser.rs +302 -20
  56. package/crates/tish_resolve/src/lib.rs +9 -0
  57. package/crates/tish_runtime/Cargo.toml +5 -0
  58. package/crates/tish_runtime/src/http.rs +28 -10
  59. package/crates/tish_runtime/src/http_fetch.rs +150 -1
  60. package/crates/tish_runtime/src/http_prefork.rs +72 -11
  61. package/crates/tish_runtime/src/lib.rs +523 -42
  62. package/crates/tish_runtime/src/timers.rs +49 -2
  63. package/crates/tish_ui/src/jsx.rs +3 -0
  64. package/crates/tish_vm/src/jit.rs +2514 -117
  65. package/crates/tish_vm/src/vm.rs +1227 -182
  66. package/package.json +1 -1
  67. package/platform/darwin-arm64/tish +0 -0
  68. package/platform/darwin-x64/tish +0 -0
  69. package/platform/linux-arm64/tish +0 -0
  70. package/platform/linux-x64/tish +0 -0
  71. package/platform/win32-x64/tish.exe +0 -0
@@ -14,6 +14,26 @@ fn next_id() -> u64 {
14
14
  NEXT_ID.fetch_add(1, Ordering::SeqCst)
15
15
  }
16
16
 
17
+ /// Maximum number of LIVE (registered, not-yet-fired) timers per worker thread. A program that keeps
18
+ /// scheduling `setTimeout`/`setInterval` without them draining would otherwise grow the registry (and
19
+ /// its retained callbacks + closed-over data) without bound (#384). Past the cap a new timer is
20
+ /// dropped rather than registered. Override with `TISH_MAX_TIMERS`; default 100k — far above any real
21
+ /// timer workload, low enough to bound memory.
22
+ fn max_live_timers() -> usize {
23
+ // Read per call (timer registration is not a hot path, and the cap exists precisely to bound the
24
+ // pathological caller): keeps the limit overridable per test without a process-global cache.
25
+ std::env::var("TISH_MAX_TIMERS")
26
+ .ok()
27
+ .and_then(|v| v.parse().ok())
28
+ .filter(|&n| n > 0)
29
+ .unwrap_or(100_000)
30
+ }
31
+
32
+ #[cfg(test)]
33
+ fn registry_len() -> usize {
34
+ REGISTRY.with(|r| r.borrow().len())
35
+ }
36
+
17
37
  struct TimerEntry {
18
38
  due: Instant,
19
39
  callback: Value,
@@ -114,7 +134,12 @@ pub fn set_timeout(args: &[Value]) -> Value {
114
134
  let id = next_id();
115
135
  let due = Instant::now() + Duration::from_millis(delay_ms);
116
136
  REGISTRY.with(|r| {
117
- r.borrow_mut().insert(
137
+ let mut reg = r.borrow_mut();
138
+ // #384: bound the live-timer count so a runaway scheduler can't grow the registry unbounded.
139
+ if reg.len() >= max_live_timers() {
140
+ return;
141
+ }
142
+ reg.insert(
118
143
  id,
119
144
  TimerEntry {
120
145
  due,
@@ -138,7 +163,12 @@ pub fn set_interval(args: &[Value]) -> Value {
138
163
  let id = next_id();
139
164
  let due = Instant::now() + Duration::from_millis(interval_ms);
140
165
  REGISTRY.with(|r| {
141
- r.borrow_mut().insert(
166
+ let mut reg = r.borrow_mut();
167
+ // #384: bound the live-timer count (see set_timeout).
168
+ if reg.len() >= max_live_timers() {
169
+ return;
170
+ }
171
+ reg.insert(
142
172
  id,
143
173
  TimerEntry {
144
174
  due,
@@ -170,3 +200,20 @@ pub fn clear_timeout(args: &[Value]) -> Value {
170
200
  pub fn clear_interval(args: &[Value]) -> Value {
171
201
  clear_timeout(args)
172
202
  }
203
+
204
+ #[cfg(test)]
205
+ mod timer_cap_tests_384 {
206
+ use super::*;
207
+
208
+ #[test]
209
+ fn set_timeout_is_bounded_by_max_timers() {
210
+ // Each `#[test]` runs on its own thread, so REGISTRY (thread_local) starts empty here.
211
+ std::env::set_var("TISH_MAX_TIMERS", "5");
212
+ let cb = tishlang_core::native_fn(|_| Value::Null);
213
+ for _ in 0..20 {
214
+ let _ = set_timeout(&[Value::Function(cb.clone()), Value::Number(10_000.0)]);
215
+ }
216
+ assert_eq!(registry_len(), 5, "live timers must be capped at TISH_MAX_TIMERS");
217
+ std::env::remove_var("TISH_MAX_TIMERS");
218
+ }
219
+ }
@@ -240,6 +240,7 @@ fn collect_fun_decl_names_stmt(stmt: &Statement, names: &mut HashSet<String>) {
240
240
  Statement::Export { declaration, .. } => match declaration.as_ref() {
241
241
  ExportDeclaration::Named(inner) => collect_fun_decl_names_stmt(inner, names),
242
242
  ExportDeclaration::Default(e) => collect_fun_decl_names_expr(e, names),
243
+ ExportDeclaration::ReExport { .. } => {}
243
244
  },
244
245
  Statement::Import { .. }
245
246
  | Statement::Break { .. }
@@ -682,6 +683,7 @@ fn stmt_contains_jsx_fragment(stmt: &tishlang_ast::Statement) -> bool {
682
683
  Statement::Export { declaration, .. } => match declaration.as_ref() {
683
684
  ExportDeclaration::Named(inner) => stmt_contains_jsx_fragment(inner),
684
685
  ExportDeclaration::Default(e) => expr_contains_jsx_fragment(e),
686
+ ExportDeclaration::ReExport { .. } => false,
685
687
  },
686
688
  Statement::Import { .. }
687
689
  | Statement::Break { .. }
@@ -857,6 +859,7 @@ fn stmt_contains_jsx(stmt: &tishlang_ast::Statement) -> bool {
857
859
  Statement::Export { declaration, .. } => match declaration.as_ref() {
858
860
  ExportDeclaration::Named(inner) => stmt_contains_jsx(inner),
859
861
  ExportDeclaration::Default(e) => expr_contains_jsx(e),
862
+ ExportDeclaration::ReExport { .. } => false,
860
863
  },
861
864
  Statement::Import { .. }
862
865
  | Statement::Break { .. }