@tishlang/tish-lint 2.12.0 → 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.
Files changed (88) hide show
  1. package/Cargo.toml +3 -0
  2. package/bin/tish-lint +0 -0
  3. package/crates/js_to_tish/src/transform/expr.rs +12 -2
  4. package/crates/tish/tests/fixtures/fs_parity_callbacks.tish +22 -0
  5. package/crates/tish/tests/fixtures/fs_parity_promises.tish +21 -0
  6. package/crates/tish/tests/fixtures/fs_parity_sync.tish +20 -0
  7. package/crates/tish/tests/fs_parity.rs +103 -0
  8. package/crates/tish/tests/integration_test.rs +80 -0
  9. package/crates/tish/tests/shortcircuit.rs +3 -3
  10. package/crates/tish_ast/src/ast.rs +84 -0
  11. package/crates/tish_builtins/Cargo.toml +1 -0
  12. package/crates/tish_builtins/src/array.rs +724 -72
  13. package/crates/tish_builtins/src/collections.rs +149 -40
  14. package/crates/tish_builtins/src/globals.rs +215 -25
  15. package/crates/tish_builtins/src/math.rs +65 -7
  16. package/crates/tish_builtins/src/number.rs +173 -0
  17. package/crates/tish_builtins/src/string.rs +263 -23
  18. package/crates/tish_bytecode/src/chunk.rs +7 -0
  19. package/crates/tish_bytecode/src/compiler.rs +611 -63
  20. package/crates/tish_bytecode/src/lib.rs +1 -1
  21. package/crates/tish_bytecode/src/opcode.rs +156 -2
  22. package/crates/tish_bytecode/src/serialize.rs +2 -0
  23. package/crates/tish_bytecode/tests/append_local_string_builder.rs +63 -0
  24. package/crates/tish_bytecode/tests/math_unary_intrinsic.rs +47 -0
  25. package/crates/tish_compile/src/codegen.rs +18219 -5283
  26. package/crates/tish_compile/src/infer.rs +1562 -30
  27. package/crates/tish_compile/src/lib.rs +29 -4
  28. package/crates/tish_compile/src/resolve.rs +151 -13
  29. package/crates/tish_compile/src/types.rs +224 -28
  30. package/crates/tish_compile/tests/dump_codegen.rs +21 -0
  31. package/crates/tish_compile/tests/perf_codegen_169_173.rs +8 -17
  32. package/crates/tish_compile/tests/perf_codegen_173_part3.rs +61 -0
  33. package/crates/tish_compile/tests/perf_codegen_174.rs +160 -0
  34. package/crates/tish_compile/tests/perf_codegen_175.rs +190 -0
  35. package/crates/tish_compile/tests/perf_codegen_176.rs +60 -0
  36. package/crates/tish_compile/tests/perf_codegen_177.rs +167 -0
  37. package/crates/tish_compile/tests/perf_codegen_178.rs +114 -0
  38. package/crates/tish_compile/tests/perf_codegen_178_rec.rs +124 -0
  39. package/crates/tish_compile/tests/perf_codegen_181.rs +36 -0
  40. package/crates/tish_compile/tests/perf_codegen_320.rs +211 -0
  41. package/crates/tish_compile/tests/perf_codegen_module_const_forof.rs +40 -0
  42. package/crates/tish_compile_js/src/codegen.rs +94 -3
  43. package/crates/tish_compile_js/src/tests_jsx.rs +27 -0
  44. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +115 -2
  45. package/crates/tish_core/Cargo.toml +4 -0
  46. package/crates/tish_core/src/json.rs +109 -6
  47. package/crates/tish_core/src/lib.rs +222 -2
  48. package/crates/tish_core/src/shape.rs +4 -2
  49. package/crates/tish_core/src/uri.rs +45 -0
  50. package/crates/tish_core/src/value.rs +571 -35
  51. package/crates/tish_core/src/vmref.rs +14 -0
  52. package/crates/tish_eval/Cargo.toml +2 -1
  53. package/crates/tish_eval/src/eval.rs +1328 -101
  54. package/crates/tish_eval/src/natives.rs +283 -18
  55. package/crates/tish_eval/src/regex.rs +47 -1
  56. package/crates/tish_eval/src/value.rs +76 -21
  57. package/crates/tish_ffi/src/lib.rs +11 -1
  58. package/crates/tish_ffi/tests/double_free.rs +35 -0
  59. package/crates/tish_fmt/src/lib.rs +94 -1
  60. package/crates/tish_lexer/src/lib.rs +76 -0
  61. package/crates/tish_lexer/src/token.rs +4 -0
  62. package/crates/tish_lint/Cargo.toml +1 -1
  63. package/crates/tish_lint/src/lib.rs +126 -0
  64. package/crates/tish_lsp/README.md +2 -1
  65. package/crates/tish_lsp/src/main.rs +378 -28
  66. package/crates/tish_native/src/build.rs +41 -0
  67. package/crates/tish_opt/src/lib.rs +20 -1
  68. package/crates/tish_parser/Cargo.toml +4 -0
  69. package/crates/tish_parser/src/lib.rs +68 -0
  70. package/crates/tish_parser/src/parser.rs +479 -28
  71. package/crates/tish_resolve/src/lib.rs +75 -5
  72. package/crates/tish_runtime/Cargo.toml +10 -1
  73. package/crates/tish_runtime/src/fs_ext.rs +359 -0
  74. package/crates/tish_runtime/src/http.rs +28 -10
  75. package/crates/tish_runtime/src/http_fetch.rs +150 -1
  76. package/crates/tish_runtime/src/http_hyper.rs +41 -18
  77. package/crates/tish_runtime/src/http_prefork.rs +72 -11
  78. package/crates/tish_runtime/src/lib.rs +651 -51
  79. package/crates/tish_runtime/src/timers.rs +49 -2
  80. package/crates/tish_ui/src/jsx.rs +21 -3
  81. package/crates/tish_vm/src/jit.rs +2514 -117
  82. package/crates/tish_vm/src/vm.rs +1479 -224
  83. package/package.json +1 -1
  84. package/platform/darwin-arm64/tish-lint +0 -0
  85. package/platform/darwin-x64/tish-lint +0 -0
  86. package/platform/linux-arm64/tish-lint +0 -0
  87. package/platform/linux-x64/tish-lint +0 -0
  88. package/platform/win32-x64/tish-lint.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
+ }
@@ -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
  }
@@ -240,6 +245,7 @@ fn collect_fun_decl_names_stmt(stmt: &Statement, names: &mut HashSet<String>) {
240
245
  Statement::Export { declaration, .. } => match declaration.as_ref() {
241
246
  ExportDeclaration::Named(inner) => collect_fun_decl_names_stmt(inner, names),
242
247
  ExportDeclaration::Default(e) => collect_fun_decl_names_expr(e, names),
248
+ ExportDeclaration::ReExport { .. } => {}
243
249
  },
244
250
  Statement::Import { .. }
245
251
  | Statement::Break { .. }
@@ -645,7 +651,12 @@ fn stmt_contains_jsx_fragment(stmt: &tishlang_ast::Statement) -> bool {
645
651
  || update.as_ref().is_some_and(expr_contains_jsx_fragment)
646
652
  || stmt_contains_jsx_fragment(body)
647
653
  }
648
- Statement::ForOf { iterable, body, .. } => {
654
+ Statement::ForOf { iterable, body, .. }
655
+ | Statement::ForIn {
656
+ object: iterable,
657
+ body,
658
+ ..
659
+ } => {
649
660
  expr_contains_jsx_fragment(iterable) || stmt_contains_jsx_fragment(body)
650
661
  }
651
662
  Statement::Switch {
@@ -682,6 +693,7 @@ fn stmt_contains_jsx_fragment(stmt: &tishlang_ast::Statement) -> bool {
682
693
  Statement::Export { declaration, .. } => match declaration.as_ref() {
683
694
  ExportDeclaration::Named(inner) => stmt_contains_jsx_fragment(inner),
684
695
  ExportDeclaration::Default(e) => expr_contains_jsx_fragment(e),
696
+ ExportDeclaration::ReExport { .. } => false,
685
697
  },
686
698
  Statement::Import { .. }
687
699
  | Statement::Break { .. }
@@ -825,7 +837,12 @@ fn stmt_contains_jsx(stmt: &tishlang_ast::Statement) -> bool {
825
837
  || update.as_ref().is_some_and(expr_contains_jsx)
826
838
  || stmt_contains_jsx(body)
827
839
  }
828
- Statement::ForOf { iterable, body, .. } => {
840
+ Statement::ForOf { iterable, body, .. }
841
+ | Statement::ForIn {
842
+ object: iterable,
843
+ body,
844
+ ..
845
+ } => {
829
846
  expr_contains_jsx(iterable) || stmt_contains_jsx(body)
830
847
  }
831
848
  Statement::Switch {
@@ -857,6 +874,7 @@ fn stmt_contains_jsx(stmt: &tishlang_ast::Statement) -> bool {
857
874
  Statement::Export { declaration, .. } => match declaration.as_ref() {
858
875
  ExportDeclaration::Named(inner) => stmt_contains_jsx(inner),
859
876
  ExportDeclaration::Default(e) => expr_contains_jsx(e),
877
+ ExportDeclaration::ReExport { .. } => false,
860
878
  },
861
879
  Statement::Import { .. }
862
880
  | Statement::Break { .. }