@tishlang/tish 1.7.0 → 1.8.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 (95) hide show
  1. package/Cargo.toml +1 -0
  2. package/README.md +2 -0
  3. package/bin/tish +0 -0
  4. package/crates/js_to_tish/src/transform/expr.rs +28 -8
  5. package/crates/js_to_tish/src/transform/stmt.rs +49 -22
  6. package/crates/tish/Cargo.toml +15 -5
  7. package/crates/tish/src/cargo_native_registry.rs +29 -0
  8. package/crates/tish/src/cli_help.rs +16 -10
  9. package/crates/tish/src/main.rs +87 -32
  10. package/crates/tish/src/repl_completion.rs +3 -3
  11. package/crates/tish/tests/cargo_example_compile.rs +1 -1
  12. package/crates/tish/tests/integration_test.rs +19 -7
  13. package/crates/tish/tests/shortcircuit.rs +1 -1
  14. package/crates/tish_ast/src/ast.rs +80 -9
  15. package/crates/tish_build_utils/Cargo.toml +4 -0
  16. package/crates/tish_build_utils/src/lib.rs +105 -2
  17. package/crates/tish_builtins/Cargo.toml +5 -1
  18. package/crates/tish_builtins/src/array.rs +13 -12
  19. package/crates/tish_builtins/src/construct.rs +34 -33
  20. package/crates/tish_builtins/src/globals.rs +12 -11
  21. package/crates/tish_builtins/src/helpers.rs +2 -1
  22. package/crates/tish_builtins/src/object.rs +3 -2
  23. package/crates/tish_builtins/src/string.rs +73 -3
  24. package/crates/tish_bytecode/src/compiler.rs +12 -14
  25. package/crates/tish_bytecode/src/opcode.rs +12 -3
  26. package/crates/tish_compile/Cargo.toml +1 -0
  27. package/crates/tish_compile/src/codegen.rs +745 -199
  28. package/crates/tish_compile/src/infer.rs +6 -0
  29. package/crates/tish_compile/src/lib.rs +4 -3
  30. package/crates/tish_compile/src/resolve.rs +180 -82
  31. package/crates/tish_compile/src/types.rs +175 -11
  32. package/crates/tish_compile_js/Cargo.toml +1 -0
  33. package/crates/tish_compile_js/src/codegen.rs +152 -29
  34. package/crates/tish_compile_js/src/lib.rs +3 -1
  35. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +31 -12
  36. package/crates/tish_core/Cargo.toml +8 -0
  37. package/crates/tish_core/src/json.rs +102 -53
  38. package/crates/tish_core/src/lib.rs +3 -1
  39. package/crates/tish_core/src/macros.rs +5 -5
  40. package/crates/tish_core/src/value.rs +53 -15
  41. package/crates/tish_core/src/vmref.rs +178 -0
  42. package/crates/tish_eval/Cargo.toml +17 -2
  43. package/crates/tish_eval/src/eval.rs +90 -28
  44. package/crates/tish_eval/src/http.rs +61 -0
  45. package/crates/tish_eval/src/lib.rs +3 -3
  46. package/crates/tish_eval/src/natives.rs +41 -0
  47. package/crates/tish_eval/src/value.rs +7 -3
  48. package/crates/tish_eval/src/value_convert.rs +13 -5
  49. package/crates/tish_fmt/src/lib.rs +120 -30
  50. package/crates/tish_lexer/src/lib.rs +20 -5
  51. package/crates/tish_lexer/src/token.rs +4 -0
  52. package/crates/tish_llvm/src/lib.rs +3 -1
  53. package/crates/tish_lsp/Cargo.toml +4 -1
  54. package/crates/tish_lsp/README.md +1 -1
  55. package/crates/tish_lsp/src/builtin_goto.rs +261 -0
  56. package/crates/tish_lsp/src/import_goto.rs +549 -0
  57. package/crates/tish_lsp/src/main.rs +502 -102
  58. package/crates/tish_native/src/build.rs +3 -2
  59. package/crates/tish_native/src/lib.rs +6 -2
  60. package/crates/tish_opt/src/lib.rs +17 -2
  61. package/crates/tish_parser/src/lib.rs +10 -3
  62. package/crates/tish_parser/src/parser.rs +346 -56
  63. package/crates/tish_resolve/Cargo.toml +13 -0
  64. package/crates/tish_resolve/src/lib.rs +3436 -0
  65. package/crates/tish_resolve/src/pos.rs +133 -0
  66. package/crates/tish_runtime/Cargo.toml +68 -3
  67. package/crates/tish_runtime/src/http.rs +1123 -141
  68. package/crates/tish_runtime/src/http_fetch.rs +15 -14
  69. package/crates/tish_runtime/src/http_hyper.rs +418 -0
  70. package/crates/tish_runtime/src/http_prefork.rs +189 -0
  71. package/crates/tish_runtime/src/lib.rs +159 -29
  72. package/crates/tish_runtime/src/promise.rs +199 -36
  73. package/crates/tish_runtime/src/promise_io.rs +2 -1
  74. package/crates/tish_runtime/src/timers.rs +37 -1
  75. package/crates/tish_runtime/src/ws.rs +26 -28
  76. package/crates/tish_ui/src/jsx.rs +279 -8
  77. package/crates/tish_ui/src/lib.rs +5 -2
  78. package/crates/tish_ui/src/runtime/hooks.rs +406 -45
  79. package/crates/tish_ui/src/runtime/mod.rs +36 -9
  80. package/crates/tish_vm/Cargo.toml +15 -5
  81. package/crates/tish_vm/src/vm.rs +506 -259
  82. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +3 -1
  83. package/crates/tish_wasm/src/lib.rs +17 -14
  84. package/crates/tish_wasm_runtime/Cargo.toml +2 -1
  85. package/crates/tish_wasm_runtime/src/lib.rs +1 -1
  86. package/crates/tishlang_cargo_bindgen/Cargo.toml +1 -0
  87. package/crates/tishlang_cargo_bindgen/src/discover.rs +68 -0
  88. package/crates/tishlang_cargo_bindgen/src/lib.rs +5 -4
  89. package/justfile +8 -0
  90. package/package.json +1 -1
  91. package/platform/darwin-arm64/tish +0 -0
  92. package/platform/darwin-x64/tish +0 -0
  93. package/platform/linux-arm64/tish +0 -0
  94. package/platform/linux-x64/tish +0 -0
  95. package/platform/win32-x64/tish.exe +0 -0
@@ -120,7 +120,9 @@ fn merged_module_program_bytecode_matches_parse_for_string_or_fixture() {
120
120
  let src = std::fs::read_to_string(&fixture).expect("read fixture");
121
121
  let modules = tishlang_compile::resolve_project(&fixture, Some(fixture.parent().unwrap()))
122
122
  .expect("resolve");
123
- let merged = tishlang_compile::merge_modules(modules).expect("merge");
123
+ let merged = tishlang_compile::merge_modules(modules)
124
+ .expect("merge")
125
+ .program;
124
126
  let flat = tishlang_parser::parse(&src).expect("parse");
125
127
  let m_opt = tishlang_opt::optimize(&merged);
126
128
  let f_opt = tishlang_opt::optimize(&flat);
@@ -3,6 +3,7 @@
3
3
  //! Compiles Tish to bytecode, then produces a .wasm VM binary + loader.
4
4
  //! The VM runs in the browser; your program runs as serialized bytecode.
5
5
 
6
+ use std::collections::BTreeSet;
6
7
  use std::path::Path;
7
8
  use std::process::Command;
8
9
 
@@ -43,7 +44,9 @@ fn resolve_and_compile_to_chunk(
43
44
  message: e.to_string(),
44
45
  })?;
45
46
  let program = {
46
- let prog = merge_modules(modules).map_err(|e| WasmError {
47
+ let prog = merge_modules(modules)
48
+ .map(|m| m.program)
49
+ .map_err(|e| WasmError {
47
50
  message: e.to_string(),
48
51
  })?;
49
52
  if optimize {
@@ -227,7 +230,7 @@ pub fn compile_to_wasi(
227
230
  let (chunk, program) = resolve_and_compile_to_chunk(entry_path, project_root, optimize)?;
228
231
  if has_external_native_imports(&program) {
229
232
  return Err(WasmError {
230
- message: "WASI backend does not support external native imports (tish:egui, @scope/pkg). Built-in tish:fs, tish:http, tish:process are supported.".to_string(),
233
+ message: "WASI backend does not support external native imports (tish:egui, @scope/pkg). Built-in tish:fs, tish:http, tish:process, tish:timers are supported.".to_string(),
231
234
  });
232
235
  }
233
236
  let wasi_features = extract_native_import_features(&program);
@@ -274,18 +277,18 @@ pub fn compile_to_wasi(
274
277
  .to_string_lossy()
275
278
  .replace('\\', "/");
276
279
 
277
- let features_str = if wasi_features.is_empty() {
278
- String::new()
279
- } else {
280
- format!(
281
- ", features = [{}]",
282
- wasi_features
283
- .iter()
284
- .map(|f| format!("{:?}", f))
285
- .collect::<Vec<_>>()
286
- .join(", ")
287
- )
288
- };
280
+ // Bundled perf (`tests/main.tish`) and many scripts use global setTimeout without a top-level
281
+ // `import` (so `extract_native_import_features` is empty). Always link timers for WASI VM.
282
+ let mut wasi_feature_set: BTreeSet<String> = wasi_features.into_iter().collect();
283
+ wasi_feature_set.insert("timers".to_string());
284
+ let features_str = format!(
285
+ ", features = [{}]",
286
+ wasi_feature_set
287
+ .iter()
288
+ .map(|f| format!("{:?}", f))
289
+ .collect::<Vec<_>>()
290
+ .join(", ")
291
+ );
289
292
  let cargo_toml = format!(
290
293
  r#"[package]
291
294
  name = "tish_wasi_{stem}"
@@ -12,10 +12,11 @@ crate-type = ["cdylib", "rlib"]
12
12
  [features]
13
13
  # For wasm32-unknown-unknown (browser): wasm-bindgen, console output
14
14
  browser = ["dep:wasm-bindgen", "tishlang_vm/wasm"]
15
- # Built-in modules for WASI (wasm32-wasip1): file I/O, process, http
15
+ # Built-in modules for WASI (wasm32-wasip1): file I/O, process, http, timers
16
16
  fs = ["tishlang_vm/fs"]
17
17
  process = ["tishlang_vm/process"]
18
18
  http = ["tishlang_vm/http"]
19
+ timers = ["tishlang_vm/timers"]
19
20
 
20
21
  [dependencies]
21
22
  tishlang_bytecode = { path = "../tish_bytecode", version = ">=0.1" }
@@ -2,7 +2,7 @@
2
2
  //!
3
3
  //! Two targets:
4
4
  //! - **Browser** (wasm32-unknown-unknown): use `--features browser`, wasm-bindgen, console output
5
- //! - **WASI/Wasmtime** (wasm32-wasi): no features, println! via WASI, run with `wasmtime app.wasm`
5
+ //! - **WASI/Wasmtime** (wasm32-wasip1): optional `timers` / `http` / … via Cargo features; `compile_to_wasi` enables `timers` by default.
6
6
 
7
7
  use tishlang_bytecode::deserialize;
8
8
  use tishlang_vm::Vm;
@@ -18,6 +18,7 @@ path = "src/lib.rs"
18
18
  cargo_metadata = "0.19"
19
19
  clap = { version = "4.6", features = ["derive", "color"] }
20
20
  pathdiff = "0.2"
21
+ proc-macro2 = { version = "1.0", features = ["span-locations"] }
21
22
  serde_json = "1"
22
23
  syn = { version = "2.0", features = ["full", "extra-traits"] }
23
24
  tempfile = "3"
@@ -50,3 +50,71 @@ pub fn discover_public_functions(crate_root: &Path) -> Result<HashMap<String, It
50
50
 
51
51
  Ok(map.into_iter().map(|(k, (_, v))| (k, v)).collect())
52
52
  }
53
+
54
+ /// On-disk location of a top-level `pub fn {fn_name}` under `crate_root/src` (LSP line/column, 0-based).
55
+ ///
56
+ /// Requires `proc-macro2` built with `span-locations` (this crate enables it) so spans from
57
+ /// `syn::parse_file` carry line/column.
58
+ pub fn rust_public_fn_location(
59
+ crate_root: &Path,
60
+ fn_name: &str,
61
+ ) -> Result<(PathBuf, u32, u32), String> {
62
+ let src = crate_root.join("src");
63
+ if !src.is_dir() {
64
+ return Err(format!("no src/ under {}", crate_root.display()));
65
+ }
66
+
67
+ for entry in WalkDir::new(&src)
68
+ .into_iter()
69
+ .filter_map(|e| e.ok())
70
+ .filter(|e| e.path().extension().map(|x| x == "rs").unwrap_or(false))
71
+ {
72
+ let path = entry.path();
73
+ let text = fs::read_to_string(path).map_err(|e| format!("read {}: {}", path.display(), e))?;
74
+ let file = syn::parse_file(&text).map_err(|e| format!("parse {}: {}", path.display(), e))?;
75
+
76
+ for item in file.items {
77
+ if let Item::Fn(f) = item {
78
+ if !is_pub(&f.vis) {
79
+ continue;
80
+ }
81
+ if f.sig.ident != fn_name {
82
+ continue;
83
+ }
84
+ let lc = f.sig.ident.span().start();
85
+ let line = u32::try_from(lc.line)
86
+ .map_err(|_| "span line out of range".to_string())?
87
+ .saturating_sub(1);
88
+ let col = u32::try_from(lc.column).map_err(|_| "span column out of range".to_string())?;
89
+ return Ok((path.to_path_buf(), line, col));
90
+ }
91
+ }
92
+ }
93
+
94
+ Err(format!(
95
+ "no public fn `{}` found under {}/src",
96
+ fn_name,
97
+ crate_root.display()
98
+ ))
99
+ }
100
+
101
+ #[cfg(test)]
102
+ mod tests {
103
+ use super::*;
104
+ use tempfile::tempdir;
105
+
106
+ #[test]
107
+ fn rust_public_fn_location_finds_fn() {
108
+ let tmp = tempdir().unwrap();
109
+ let src = tmp.path().join("src");
110
+ fs::create_dir_all(&src).unwrap();
111
+ fs::write(
112
+ src.join("lib.rs"),
113
+ "// comment\npub fn hello_tish_export() -> i32 { 0 }\n",
114
+ )
115
+ .unwrap();
116
+ let (path, line, _col) = rust_public_fn_location(tmp.path(), "hello_tish_export").unwrap();
117
+ assert!(path.ends_with("lib.rs"));
118
+ assert_eq!(line, 1);
119
+ }
120
+ }
@@ -21,6 +21,7 @@ pub mod infer;
21
21
  mod metadata;
22
22
 
23
23
  pub use classify::SignatureClass;
24
+ pub use discover::rust_public_fn_location;
24
25
  pub use metadata::{resolve_dependency_from_manifest, resolve_registry_dependency, ResolvedDependency};
25
26
 
26
27
  use std::fs;
@@ -181,7 +182,7 @@ fn render_generated_lib(
181
182
  use std::cell::RefCell;\n\
182
183
  use std::rc::Rc;\n\
183
184
  use std::sync::Arc;\n\
184
- use tishlang_runtime::{ObjectMap, Value};\n\n",
185
+ use tishlang_runtime::{ObjectMap, Value, VmRef};\n\n",
185
186
  );
186
187
 
187
188
  out.push_str(&format!(
@@ -244,15 +245,15 @@ fn json_to_tish(v: serde_json::Value) -> Value {
244
245
  serde_json::Value::Bool(b) => Value::Bool(b),
245
246
  serde_json::Value::Number(n) => Value::Number(n.as_f64().unwrap_or(0.0)),
246
247
  serde_json::Value::String(s) => Value::String(s.into()),
247
- serde_json::Value::Array(a) => Value::Array(Rc::new(RefCell::new(
248
+ serde_json::Value::Array(a) => Value::Array(VmRef::new(
248
249
  a.into_iter().map(json_to_tish).collect(),
249
- ))),
250
+ )),
250
251
  serde_json::Value::Object(m) => {
251
252
  let mut om = ObjectMap::default();
252
253
  for (k, v) in m {
253
254
  om.insert(Arc::from(k), json_to_tish(v));
254
255
  }
255
- Value::Object(Rc::new(RefCell::new(om)))
256
+ Value::Object(VmRef::new(om))
256
257
  }
257
258
  }
258
259
  }
package/justfile CHANGED
@@ -250,6 +250,14 @@ optional-chaining-profile:
250
250
  perf *ARGS:
251
251
  ./scripts/run_performance_manual.sh {{ARGS}}
252
252
 
253
+ # Bundled perf suite: per-test table + whole-program timings (tests/main.tish); add --verbose for full stdout
254
+ perf-suite *ARGS:
255
+ ./scripts/run_performance_suite.sh {{ARGS}}
256
+
257
+ # Regenerate tests/main.tish + tests/main.js after changing paired pure perf tests
258
+ perf-suite-gen:
259
+ ./scripts/generate_perf_ci_main.sh
260
+
253
261
  # Show binary sizes for different builds
254
262
  sizes:
255
263
  @echo "Building secure binary..."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tishlang/tish",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Tish - minimal TS/JS-compatible language. Run, REPL, build to native or other targets.",
5
5
  "license": "PIF",
6
6
  "repository": {
Binary file
Binary file
Binary file
Binary file
Binary file