@tishlang/tish-format 1.0.12 → 1.0.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 (164) hide show
  1. package/Cargo.toml +49 -0
  2. package/LICENSE +13 -0
  3. package/README.md +138 -0
  4. package/bin/tish-format +0 -0
  5. package/crates/js_to_tish/Cargo.toml +11 -0
  6. package/crates/js_to_tish/README.md +18 -0
  7. package/crates/js_to_tish/src/error.rs +55 -0
  8. package/crates/js_to_tish/src/lib.rs +11 -0
  9. package/crates/js_to_tish/src/span_util.rs +35 -0
  10. package/crates/js_to_tish/src/transform/expr.rs +610 -0
  11. package/crates/js_to_tish/src/transform/stmt.rs +503 -0
  12. package/crates/js_to_tish/src/transform.rs +60 -0
  13. package/crates/tish/Cargo.toml +54 -0
  14. package/crates/tish/src/cargo_native_registry.rs +32 -0
  15. package/crates/tish/src/cli_help.rs +565 -0
  16. package/crates/tish/src/main.rs +781 -0
  17. package/crates/tish/src/repl_completion.rs +200 -0
  18. package/crates/tish/tests/cargo_example_compile.rs +67 -0
  19. package/crates/tish/tests/fixtures/cargo_example_project/Cargo.toml +3 -0
  20. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/Cargo.toml +11 -0
  21. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/src/lib.rs +12 -0
  22. package/crates/tish/tests/fixtures/cargo_example_project/package.json +10 -0
  23. package/crates/tish/tests/fixtures/cargo_example_project/src/main.tish +3 -0
  24. package/crates/tish/tests/integration_test.rs +1095 -0
  25. package/crates/tish/tests/run_optimize_stdout_parity.rs +50 -0
  26. package/crates/tish/tests/shortcircuit.rs +65 -0
  27. package/crates/tish_ast/Cargo.toml +9 -0
  28. package/crates/tish_ast/src/ast.rs +620 -0
  29. package/crates/tish_ast/src/lib.rs +5 -0
  30. package/crates/tish_build_utils/Cargo.toml +11 -0
  31. package/crates/tish_build_utils/src/lib.rs +577 -0
  32. package/crates/tish_builtins/Cargo.toml +20 -0
  33. package/crates/tish_builtins/src/array.rs +441 -0
  34. package/crates/tish_builtins/src/construct.rs +159 -0
  35. package/crates/tish_builtins/src/globals.rs +213 -0
  36. package/crates/tish_builtins/src/helpers.rs +35 -0
  37. package/crates/tish_builtins/src/lib.rs +16 -0
  38. package/crates/tish_builtins/src/math.rs +89 -0
  39. package/crates/tish_builtins/src/object.rs +36 -0
  40. package/crates/tish_builtins/src/string.rs +647 -0
  41. package/crates/tish_builtins/src/symbol.rs +83 -0
  42. package/crates/tish_bytecode/Cargo.toml +17 -0
  43. package/crates/tish_bytecode/src/chunk.rs +96 -0
  44. package/crates/tish_bytecode/src/compiler.rs +1760 -0
  45. package/crates/tish_bytecode/src/encoding.rs +100 -0
  46. package/crates/tish_bytecode/src/lib.rs +19 -0
  47. package/crates/tish_bytecode/src/opcode.rs +142 -0
  48. package/crates/tish_bytecode/src/peephole.rs +189 -0
  49. package/crates/tish_bytecode/src/serialize.rs +163 -0
  50. package/crates/tish_bytecode/tests/break_continue_bytecode.rs +44 -0
  51. package/crates/tish_bytecode/tests/constant_folding.rs +84 -0
  52. package/crates/tish_bytecode/tests/sort_optimization.rs +31 -0
  53. package/crates/tish_compile/Cargo.toml +26 -0
  54. package/crates/tish_compile/src/codegen.rs +5332 -0
  55. package/crates/tish_compile/src/infer.rs +292 -0
  56. package/crates/tish_compile/src/lib.rs +164 -0
  57. package/crates/tish_compile/src/resolve.rs +1388 -0
  58. package/crates/tish_compile/src/types.rs +501 -0
  59. package/crates/tish_compile_js/Cargo.toml +18 -0
  60. package/crates/tish_compile_js/examples/jsx_vdom_smoke.tish +8 -0
  61. package/crates/tish_compile_js/src/codegen.rs +871 -0
  62. package/crates/tish_compile_js/src/error.rs +20 -0
  63. package/crates/tish_compile_js/src/lib.rs +26 -0
  64. package/crates/tish_compile_js/src/tests_jsx.rs +350 -0
  65. package/crates/tish_compiler_wasm/Cargo.toml +21 -0
  66. package/crates/tish_compiler_wasm/src/lib.rs +57 -0
  67. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +473 -0
  68. package/crates/tish_core/Cargo.toml +26 -0
  69. package/crates/tish_core/src/console_style.rs +160 -0
  70. package/crates/tish_core/src/json.rs +387 -0
  71. package/crates/tish_core/src/lib.rs +17 -0
  72. package/crates/tish_core/src/macros.rs +36 -0
  73. package/crates/tish_core/src/uri.rs +118 -0
  74. package/crates/tish_core/src/value.rs +696 -0
  75. package/crates/tish_core/src/vmref.rs +178 -0
  76. package/crates/tish_cranelift/Cargo.toml +19 -0
  77. package/crates/tish_cranelift/src/lib.rs +43 -0
  78. package/crates/tish_cranelift/src/link.rs +117 -0
  79. package/crates/tish_cranelift/src/lower.rs +85 -0
  80. package/crates/tish_cranelift_runtime/Cargo.toml +25 -0
  81. package/crates/tish_cranelift_runtime/src/lib.rs +45 -0
  82. package/crates/tish_eval/Cargo.toml +45 -0
  83. package/crates/tish_eval/src/eval.rs +3717 -0
  84. package/crates/tish_eval/src/http.rs +188 -0
  85. package/crates/tish_eval/src/lib.rs +99 -0
  86. package/crates/tish_eval/src/natives.rs +399 -0
  87. package/crates/tish_eval/src/promise.rs +179 -0
  88. package/crates/tish_eval/src/regex.rs +299 -0
  89. package/crates/tish_eval/src/timers.rs +120 -0
  90. package/crates/tish_eval/src/value.rs +318 -0
  91. package/crates/tish_eval/src/value_convert.rs +111 -0
  92. package/crates/tish_fmt/Cargo.toml +16 -0
  93. package/crates/tish_fmt/src/bin/tish-fmt.rs +41 -0
  94. package/crates/tish_fmt/src/lib.rs +2101 -0
  95. package/crates/tish_jsx_web/Cargo.toml +9 -0
  96. package/crates/tish_jsx_web/README.md +5 -0
  97. package/crates/tish_jsx_web/src/lib.rs +2 -0
  98. package/crates/tish_lexer/Cargo.toml +9 -0
  99. package/crates/tish_lexer/src/lib.rs +716 -0
  100. package/crates/tish_lexer/src/token.rs +163 -0
  101. package/crates/tish_lint/Cargo.toml +18 -0
  102. package/crates/tish_lint/src/bin/tish-lint.rs +195 -0
  103. package/crates/tish_lint/src/lib.rs +289 -0
  104. package/crates/tish_llvm/Cargo.toml +13 -0
  105. package/crates/tish_llvm/src/lib.rs +115 -0
  106. package/crates/tish_lsp/Cargo.toml +25 -0
  107. package/crates/tish_lsp/README.md +26 -0
  108. package/crates/tish_lsp/src/builtin_goto.rs +362 -0
  109. package/crates/tish_lsp/src/import_goto.rs +562 -0
  110. package/crates/tish_lsp/src/main.rs +1046 -0
  111. package/crates/tish_native/Cargo.toml +16 -0
  112. package/crates/tish_native/src/build.rs +427 -0
  113. package/crates/tish_native/src/config.rs +48 -0
  114. package/crates/tish_native/src/lib.rs +416 -0
  115. package/crates/tish_opt/Cargo.toml +13 -0
  116. package/crates/tish_opt/src/lib.rs +943 -0
  117. package/crates/tish_parser/Cargo.toml +11 -0
  118. package/crates/tish_parser/src/lib.rs +332 -0
  119. package/crates/tish_parser/src/parser.rs +2304 -0
  120. package/crates/tish_pg/Cargo.toml +34 -0
  121. package/crates/tish_pg/README.md +38 -0
  122. package/crates/tish_pg/src/error.rs +52 -0
  123. package/crates/tish_pg/src/lib.rs +955 -0
  124. package/crates/tish_resolve/Cargo.toml +13 -0
  125. package/crates/tish_resolve/src/lib.rs +3561 -0
  126. package/crates/tish_resolve/src/pos.rs +141 -0
  127. package/crates/tish_runtime/Cargo.toml +96 -0
  128. package/crates/tish_runtime/src/http.rs +1298 -0
  129. package/crates/tish_runtime/src/http_fetch.rs +471 -0
  130. package/crates/tish_runtime/src/http_hyper.rs +418 -0
  131. package/crates/tish_runtime/src/http_prefork.rs +189 -0
  132. package/crates/tish_runtime/src/lib.rs +1192 -0
  133. package/crates/tish_runtime/src/native_promise.rs +15 -0
  134. package/crates/tish_runtime/src/promise.rs +248 -0
  135. package/crates/tish_runtime/src/promise_io.rs +38 -0
  136. package/crates/tish_runtime/src/timers.rs +166 -0
  137. package/crates/tish_runtime/src/ws.rs +761 -0
  138. package/crates/tish_runtime/tests/fetch_readable_stream.rs +102 -0
  139. package/crates/tish_ui/Cargo.toml +17 -0
  140. package/crates/tish_ui/src/jsx.rs +682 -0
  141. package/crates/tish_ui/src/lib.rs +20 -0
  142. package/crates/tish_ui/src/runtime/hooks.rs +569 -0
  143. package/crates/tish_ui/src/runtime/mod.rs +180 -0
  144. package/crates/tish_vm/Cargo.toml +47 -0
  145. package/crates/tish_vm/src/lib.rs +39 -0
  146. package/crates/tish_vm/src/vm.rs +2192 -0
  147. package/crates/tish_vm/tests/fixtures/or_string_cmd.tish +2 -0
  148. package/crates/tish_vm/tests/lexical_scope_declare.rs +34 -0
  149. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +150 -0
  150. package/crates/tish_wasm/Cargo.toml +15 -0
  151. package/crates/tish_wasm/src/lib.rs +424 -0
  152. package/crates/tish_wasm_runtime/Cargo.toml +37 -0
  153. package/crates/tish_wasm_runtime/src/gpu.rs +413 -0
  154. package/crates/tish_wasm_runtime/src/lib.rs +42 -0
  155. package/crates/tishlang_cargo_bindgen/Cargo.toml +26 -0
  156. package/crates/tishlang_cargo_bindgen/src/classify.rs +263 -0
  157. package/crates/tishlang_cargo_bindgen/src/discover.rs +125 -0
  158. package/crates/tishlang_cargo_bindgen/src/infer.rs +382 -0
  159. package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
  160. package/crates/tishlang_cargo_bindgen/src/main.rs +167 -0
  161. package/crates/tishlang_cargo_bindgen/src/metadata.rs +117 -0
  162. package/justfile +268 -0
  163. package/package.json +1 -1
  164. package/platform/darwin-arm64/tish-fmt +0 -0
@@ -0,0 +1,178 @@
1
+ //! Shared-mutable reference used by the Tish runtime for `Value::Array`,
2
+ //! `Value::Object`, and `Value::RegExp` payloads.
3
+ //!
4
+ //! ## Why this exists
5
+ //!
6
+ //! Tish's `Value` uses interior mutability for arrays, objects, and regex
7
+ //! state. Historically that was `Rc<RefCell<T>>`, which is fast but
8
+ //! `!Send` — so `Value` couldn't move across threads, which in turn meant
9
+ //! `serve(port, handler)` had to serialise every request through one
10
+ //! VM dispatcher thread.
11
+ //!
12
+ //! `VmRef<T>` lets the build system pick the right trade-off **per
13
+ //! compile target**:
14
+ //!
15
+ //! | feature `send-values` | `VmRef<T>` | `NativeFn` | targets |
16
+ //! |---------------------------|-------------------------|----------------------------------|--------------------------------------------------|
17
+ //! | **off** *(default)* | `Rc<RefCell<T>>` | `Rc<dyn Fn + 'static>` | wasm32, wasi, interpreter, cranelift/llvm VMs |
18
+ //! | **on** | `Arc<Mutex<T>>` | `Arc<dyn Fn + Send + Sync>` | Rust native with `http` enabled (server workloads) |
19
+ //!
20
+ //! The *API* is identical in both configurations (`borrow` / `borrow_mut`
21
+ //! / `ptr_eq` / `Clone`), so every existing call site in the workspace
22
+ //! compiles unchanged. What flips is only the underlying primitive.
23
+ //!
24
+ //! ## Why this matters for performance
25
+ //!
26
+ //! * **wasm / wasi / cranelift / llvm / interpreter**: still pure
27
+ //! `Rc<RefCell<T>>`. Zero atomic ops, no mutex churn, behaviour
28
+ //! bit-identical to the pre-migration baseline.
29
+ //! * **Rust native, non-server**: same — `send-values` only activates
30
+ //! when something in the dependency graph (usually `http`) needs it.
31
+ //! * **Rust native with server**: `Arc<Mutex<T>>` pays ~3–5 ns per
32
+ //! `borrow` in the uncontended case (single atomic CAS). On Tish's
33
+ //! hot paths — roughly 6–12 borrows per request — that's ~30–60 ns of
34
+ //! overhead. In exchange we get `N×` handler scaling across cores,
35
+ //! which recovers orders of magnitude more throughput than it costs.
36
+ //!
37
+ //! ## API surface
38
+ //!
39
+ //! ```ignore
40
+ //! let cell = VmRef::new(42);
41
+ //! *cell.borrow() + 1; // read
42
+ //! *cell.borrow_mut() = 99; // write
43
+ //! VmRef::ptr_eq(&a, &b); // identity
44
+ //! let clone = cell.clone(); // shared ownership
45
+ //! ```
46
+ //!
47
+ //! Returned guard types (`VmReadGuard<'_, T>`, `VmWriteGuard<'_, T>`) are
48
+ //! type aliases that pick `Ref`/`RefMut` or `MutexGuard` depending on the
49
+ //! feature. They both `Deref` (and, for write guards, `DerefMut`) to `T`
50
+ //! just like the underlying types.
51
+
52
+ use std::fmt;
53
+
54
+ // --------------------------------------------------------------------------
55
+ // Single-threaded backing store (default): Rc<RefCell<T>>
56
+ // --------------------------------------------------------------------------
57
+ #[cfg(not(feature = "send-values"))]
58
+ mod imp {
59
+ use std::cell::RefCell;
60
+ use std::rc::Rc;
61
+
62
+ #[derive(Default)]
63
+ pub struct VmRef<T: ?Sized>(pub(super) Rc<RefCell<T>>);
64
+
65
+ /// Read guard alias. On the single-threaded path this is a true
66
+ /// `Ref<'_, T>`, so multiple readers can coexist.
67
+ pub type ReadGuard<'a, T> = std::cell::Ref<'a, T>;
68
+ /// Write guard alias. Exclusive, `DerefMut`.
69
+ pub type WriteGuard<'a, T> = std::cell::RefMut<'a, T>;
70
+
71
+ impl<T> VmRef<T> {
72
+ #[inline]
73
+ pub fn new(value: T) -> Self {
74
+ VmRef(Rc::new(RefCell::new(value)))
75
+ }
76
+ }
77
+
78
+ impl<T: ?Sized> VmRef<T> {
79
+ #[inline]
80
+ pub fn borrow(&self) -> ReadGuard<'_, T> {
81
+ self.0.borrow()
82
+ }
83
+
84
+ #[inline]
85
+ pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
86
+ self.0.borrow_mut()
87
+ }
88
+
89
+ #[inline]
90
+ pub fn ptr_eq(a: &Self, b: &Self) -> bool {
91
+ Rc::ptr_eq(&a.0, &b.0)
92
+ }
93
+
94
+ #[inline]
95
+ pub fn strong_count(this: &Self) -> usize {
96
+ Rc::strong_count(&this.0)
97
+ }
98
+ }
99
+
100
+ impl<T: ?Sized> Clone for VmRef<T> {
101
+ #[inline]
102
+ fn clone(&self) -> Self {
103
+ VmRef(Rc::clone(&self.0))
104
+ }
105
+ }
106
+ }
107
+
108
+ // --------------------------------------------------------------------------
109
+ // Thread-safe backing store (opt-in): Arc<Mutex<T>>
110
+ // --------------------------------------------------------------------------
111
+ #[cfg(feature = "send-values")]
112
+ mod imp {
113
+ use std::sync::{Arc, Mutex};
114
+
115
+ #[derive(Default)]
116
+ pub struct VmRef<T: ?Sized>(pub(super) Arc<Mutex<T>>);
117
+
118
+ /// Read guard alias. On the multi-threaded path both readers and
119
+ /// writers share a single `MutexGuard` (exclusive access).
120
+ pub type ReadGuard<'a, T> = std::sync::MutexGuard<'a, T>;
121
+ /// Write guard alias.
122
+ pub type WriteGuard<'a, T> = std::sync::MutexGuard<'a, T>;
123
+
124
+ impl<T> VmRef<T> {
125
+ #[inline]
126
+ pub fn new(value: T) -> Self {
127
+ VmRef(Arc::new(Mutex::new(value)))
128
+ }
129
+ }
130
+
131
+ impl<T: ?Sized> VmRef<T> {
132
+ /// Acquire the inner mutex. Poisoning is swallowed — a Tish
133
+ /// handler panic already aborts the enclosing thread; there is
134
+ /// no invariant worth preserving past that point.
135
+ #[inline]
136
+ pub fn borrow(&self) -> ReadGuard<'_, T> {
137
+ self.0.lock().unwrap_or_else(|p| p.into_inner())
138
+ }
139
+
140
+ #[inline]
141
+ pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
142
+ self.0.lock().unwrap_or_else(|p| p.into_inner())
143
+ }
144
+
145
+ #[inline]
146
+ pub fn ptr_eq(a: &Self, b: &Self) -> bool {
147
+ Arc::ptr_eq(&a.0, &b.0)
148
+ }
149
+
150
+ #[inline]
151
+ pub fn strong_count(this: &Self) -> usize {
152
+ Arc::strong_count(&this.0)
153
+ }
154
+ }
155
+
156
+ impl<T: ?Sized> Clone for VmRef<T> {
157
+ #[inline]
158
+ fn clone(&self) -> Self {
159
+ VmRef(Arc::clone(&self.0))
160
+ }
161
+ }
162
+ }
163
+
164
+ pub use imp::{ReadGuard as VmReadGuard, VmRef, WriteGuard as VmWriteGuard};
165
+
166
+ impl<T: fmt::Debug> fmt::Debug for VmRef<T> {
167
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168
+ // Match `RefCell`'s debug format so snapshot-test output stays
169
+ // stable across the migration.
170
+ match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
171
+ let guard = self.borrow();
172
+ format!("{:?}", &*guard)
173
+ })) {
174
+ Ok(s) => write!(f, "RefCell {{ value: {} }}", s),
175
+ Err(_) => write!(f, "RefCell {{ value: <borrowed> }}"),
176
+ }
177
+ }
178
+ }
@@ -0,0 +1,19 @@
1
+ [package]
2
+ name = "tishlang_cranelift"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Bytecode to native via Cranelift"
6
+
7
+ license-file = { workspace = true }
8
+ repository = { workspace = true }
9
+ [dependencies]
10
+ tishlang_build_utils = { path = "../tish_build_utils", version = ">=0.1" }
11
+ cranelift = "0.130"
12
+ cranelift-codegen = "0.130"
13
+ cranelift-frontend = "0.130"
14
+ cranelift-module = "0.130"
15
+ cranelift-native = "0.130"
16
+ cranelift-object = "0.130"
17
+ target-lexicon = "0.13"
18
+ tishlang_bytecode = { path = "../tish_bytecode", version = ">=0.1" }
19
+ tishlang_core = { path = "../tish_core", version = ">=0.1" }
@@ -0,0 +1,43 @@
1
+ //! Standalone native binary: embedded bytecode + VM (Cranelift used as object builder).
2
+ //!
3
+ //! Produces an executable that runs **`tishlang_vm`** on serialized bytecode embedded in
4
+ //! the binary — not lowering of Tish opcodes to CLIF/machine code (see module docs in
5
+ //! `lower.rs`). For Rust transpile + `tishlang_runtime`, use `--native-backend rust`.
6
+
7
+ mod link;
8
+ mod lower;
9
+
10
+ pub use link::link_to_binary;
11
+
12
+ use std::path::Path;
13
+
14
+ use tishlang_bytecode::Chunk;
15
+
16
+ /// Error from Cranelift compilation.
17
+ #[derive(Debug)]
18
+ pub struct CraneliftError {
19
+ pub message: String,
20
+ }
21
+
22
+ impl std::fmt::Display for CraneliftError {
23
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24
+ write!(f, "{}", self.message)
25
+ }
26
+ }
27
+
28
+ impl std::error::Error for CraneliftError {}
29
+
30
+ /// Build a native binary that embeds `chunk` and runs it with the bytecode VM.
31
+ /// `features` are passed to `tishlang_cranelift_runtime` (e.g. fs, process, http).
32
+ pub fn compile_chunk_to_native(
33
+ chunk: &Chunk,
34
+ output_path: &Path,
35
+ features: &[String],
36
+ ) -> Result<(), CraneliftError> {
37
+ let object_path = output_path.with_extension("o");
38
+ lower::lower_and_emit(chunk, &object_path)?;
39
+ link::link_to_binary(&object_path, output_path, features)?;
40
+ // Clean up .o file
41
+ let _ = std::fs::remove_file(&object_path);
42
+ Ok(())
43
+ }
@@ -0,0 +1,117 @@
1
+ //! Link object file with runtime to produce final binary.
2
+ //!
3
+ //! Uses Cargo to build a small binary that links our .o and runs the chunk.
4
+
5
+ use std::fs;
6
+ use std::path::Path;
7
+
8
+ use crate::CraneliftError;
9
+
10
+ pub fn link_to_binary(
11
+ object_path: &Path,
12
+ output_path: &Path,
13
+ features: &[String],
14
+ ) -> Result<(), CraneliftError> {
15
+ let workspace_root =
16
+ tishlang_build_utils::find_workspace_root().map_err(|e| CraneliftError { message: e })?;
17
+ let out_name = output_path
18
+ .file_stem()
19
+ .and_then(|s| s.to_str())
20
+ .unwrap_or("tish_out");
21
+ let build_dir = tishlang_build_utils::create_build_dir("tishlang_cranelift_build", out_name)
22
+ .map_err(|e| CraneliftError { message: e })?;
23
+
24
+ let object_path_str = object_path
25
+ .canonicalize()
26
+ .map_err(|e| CraneliftError {
27
+ message: format!("Cannot canonicalize object path: {}", e),
28
+ })?
29
+ .display()
30
+ .to_string()
31
+ .replace('\\', "/");
32
+
33
+ // tishlang_cranelift_runtime crate lives in crates/tish_cranelift_runtime
34
+ let runtime_path = workspace_root
35
+ .join("crates")
36
+ .join("tish_cranelift_runtime")
37
+ .canonicalize()
38
+ .map_err(|e| CraneliftError {
39
+ message: format!("Cannot find tishlang_cranelift_runtime: {}", e),
40
+ })?
41
+ .display()
42
+ .to_string()
43
+ .replace('\\', "/");
44
+
45
+ let features_str = if features.is_empty() {
46
+ String::new()
47
+ } else {
48
+ format!(
49
+ ", features = [{}]",
50
+ features
51
+ .iter()
52
+ .map(|f| format!("{:?}", f))
53
+ .collect::<Vec<_>>()
54
+ .join(", ")
55
+ )
56
+ };
57
+ let cargo_toml_fixed = format!(
58
+ r#"[package]
59
+ name = "tishlang_cranelift_out"
60
+ version = "0.1.0"
61
+ edition = "2021"
62
+
63
+ [[bin]]
64
+ name = "{}"
65
+ path = "src/main.rs"
66
+
67
+ [dependencies]
68
+ tishlang_cranelift_runtime = {{ path = {:?}{} }}
69
+ "#,
70
+ out_name, runtime_path, features_str
71
+ );
72
+
73
+ let main_rs = r#"
74
+ extern "C" {
75
+ static tish_chunk_data: [u8; 1];
76
+ static tish_chunk_len: u64;
77
+ }
78
+
79
+ fn main() {
80
+ let len = unsafe { tish_chunk_len } as usize;
81
+ let ptr = unsafe { tish_chunk_data.as_ptr() };
82
+ let exit_code = tishlang_cranelift_runtime::tish_run_chunk(ptr, len);
83
+ std::process::exit(exit_code);
84
+ }
85
+ "#;
86
+
87
+ let build_rs = format!(
88
+ r#"
89
+ fn main() {{
90
+ println!("cargo:rustc-link-arg={}");
91
+ }}
92
+ "#,
93
+ object_path_str
94
+ );
95
+
96
+ fs::write(build_dir.join("Cargo.toml"), cargo_toml_fixed).map_err(|e| CraneliftError {
97
+ message: format!("Cannot write Cargo.toml: {}", e),
98
+ })?;
99
+ fs::write(build_dir.join("src/main.rs"), main_rs).map_err(|e| CraneliftError {
100
+ message: format!("Cannot write main.rs: {}", e),
101
+ })?;
102
+ fs::write(build_dir.join("build.rs"), build_rs).map_err(|e| CraneliftError {
103
+ message: format!("Cannot write build.rs: {}", e),
104
+ })?;
105
+
106
+ tishlang_build_utils::run_cargo_build(&build_dir, None, None)
107
+ .map_err(|e| CraneliftError { message: e })?;
108
+
109
+ let binary_dir = build_dir.join("target").join("release");
110
+ let binary = tishlang_build_utils::find_release_binary(&binary_dir, out_name)
111
+ .map_err(|e| CraneliftError { message: e })?;
112
+ let target = tishlang_build_utils::resolve_output_path(output_path, out_name);
113
+ tishlang_build_utils::copy_binary_to_output(&binary, &target)
114
+ .map_err(|e| CraneliftError { message: e })?;
115
+
116
+ Ok(())
117
+ }
@@ -0,0 +1,85 @@
1
+ //! Embed serialized bytecode in an object file for the standalone native binary.
2
+ //!
3
+ //! **This is not AOT compilation of Tish into Cranelift IR.** The chunk is stored as
4
+ //! read-only data (`tish_chunk_data`, `tish_chunk_len`). The link step produces an
5
+ //! executable that **deserializes the chunk and runs `tishlang_vm`** — same VM as
6
+ //! `tish run --backend vm`. Cranelift is only the object-file emitter for that blob.
7
+
8
+ use std::path::Path;
9
+
10
+ use cranelift::codegen::settings;
11
+ use cranelift::codegen::settings::Configurable;
12
+ use cranelift_module::{DataDescription, Linkage, Module};
13
+ use cranelift_object::{ObjectBuilder, ObjectModule};
14
+
15
+ use tishlang_bytecode::{serialize, Chunk};
16
+
17
+ use crate::CraneliftError;
18
+
19
+ pub fn lower_and_emit(chunk: &Chunk, object_path: &Path) -> Result<(), CraneliftError> {
20
+ let mut settings_builder = settings::builder();
21
+ settings_builder
22
+ .set("opt_level", "speed")
23
+ .map_err(|_| CraneliftError {
24
+ message: "Failed to set opt_level".to_string(),
25
+ })?;
26
+ let flags = settings::Flags::new(settings_builder);
27
+
28
+ let isa_builder = cranelift_native::builder().map_err(|e| CraneliftError {
29
+ message: format!("Failed to build ISA: {}", e),
30
+ })?;
31
+ let isa = isa_builder.finish(flags).map_err(|e| CraneliftError {
32
+ message: format!("Failed to finish ISA: {}", e),
33
+ })?;
34
+
35
+ let object_builder = ObjectBuilder::new(
36
+ isa,
37
+ "tishlang_cranelift",
38
+ cranelift_module::default_libcall_names(),
39
+ )
40
+ .map_err(|e| CraneliftError {
41
+ message: format!("Failed to create ObjectBuilder: {}", e),
42
+ })?;
43
+ let mut module = ObjectModule::new(object_builder);
44
+
45
+ // Serialize chunk and emit as data - link step will build a Rust binary that reads it
46
+ let chunk_data = serialize(chunk);
47
+ let chunk_len = chunk_data.len() as u64;
48
+ let data_id = module
49
+ .declare_data("tish_chunk_data", Linkage::Export, false, false)
50
+ .map_err(|e| CraneliftError {
51
+ message: format!("Failed to declare chunk data: {}", e),
52
+ })?;
53
+ let mut data_desc = DataDescription::new();
54
+ data_desc.define(chunk_data.into_boxed_slice());
55
+ module
56
+ .define_data(data_id, &data_desc)
57
+ .map_err(|e| CraneliftError {
58
+ message: format!("Failed to define chunk data: {}", e),
59
+ })?;
60
+
61
+ let len_data = chunk_len.to_le_bytes();
62
+ let len_id = module
63
+ .declare_data("tish_chunk_len", Linkage::Export, false, false)
64
+ .map_err(|e| CraneliftError {
65
+ message: format!("Failed to declare chunk len: {}", e),
66
+ })?;
67
+ let mut len_desc = DataDescription::new();
68
+ len_desc.define(len_data.to_vec().into_boxed_slice());
69
+ module
70
+ .define_data(len_id, &len_desc)
71
+ .map_err(|e| CraneliftError {
72
+ message: format!("Failed to define chunk len: {}", e),
73
+ })?;
74
+
75
+ let object_product = module.finish();
76
+ let bytes = object_product.emit().map_err(|e| CraneliftError {
77
+ message: format!("Failed to emit object: {}", e),
78
+ })?;
79
+
80
+ std::fs::write(object_path, bytes).map_err(|e| CraneliftError {
81
+ message: format!("Failed to write object file: {}", e),
82
+ })?;
83
+
84
+ Ok(())
85
+ }
@@ -0,0 +1,25 @@
1
+ [package]
2
+ name = "tishlang_cranelift_runtime"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Runtime for Cranelift-compiled Tish bytecode"
6
+
7
+ license-file = { workspace = true }
8
+ repository = { workspace = true }
9
+ [features]
10
+ default = []
11
+ fs = ["tishlang_vm/fs"]
12
+ process = ["tishlang_vm/process"]
13
+ http = ["tishlang_vm/http"]
14
+ promise = ["tishlang_vm/promise"]
15
+ timers = ["tishlang_vm/timers"]
16
+ ws = ["tishlang_vm/ws"]
17
+ regex = ["tishlang_vm/regex"]
18
+
19
+ [lib]
20
+ crate-type = ["staticlib", "rlib"]
21
+
22
+ [dependencies]
23
+ tishlang_bytecode = { path = "../tish_bytecode", version = ">=0.1" }
24
+ tishlang_vm = { path = "../tish_vm", version = ">=0.1" }
25
+ tishlang_core = { path = "../tish_core", version = ">=0.1" }
@@ -0,0 +1,45 @@
1
+ //! Runtime linked into the `tish build --native-backend cranelift` executable.
2
+ //!
3
+ //! **`tish_run_chunk`** deserializes embedded bytecode and runs **`tishlang_vm`** — the same
4
+ //! execution engine as `tish run --backend vm`. The crate name is historical; this is not
5
+ //! running CLIF-emitted machine code for each Tish opcode.
6
+
7
+ use tishlang_bytecode::deserialize;
8
+ use tishlang_vm::Vm;
9
+
10
+ /// Serialization format:
11
+ /// - u64: code len
12
+ /// - bytes: code
13
+ /// - u64: constants count
14
+ /// - for each constant: u8 tag + payload
15
+ /// - u64: names count
16
+ /// - for each name: u64 len + bytes
17
+ ///
18
+ /// Rust-callable wrapper. Run serialized chunk data. Returns exit code (0 on success).
19
+ pub fn tish_run_chunk(ptr: *const u8, len: usize) -> i32 {
20
+ tish_run_chunk_impl(ptr, len)
21
+ }
22
+
23
+ #[no_mangle]
24
+ extern "C" fn tish_run_chunk_impl(ptr: *const u8, len: usize) -> i32 {
25
+ if ptr.is_null() || len < 8 {
26
+ return 1;
27
+ }
28
+ let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
29
+ match deserialize(slice) {
30
+ Ok(chunk) => {
31
+ let mut vm = Vm::new();
32
+ match vm.run(&chunk) {
33
+ Ok(_) => 0,
34
+ Err(e) => {
35
+ eprintln!("Runtime error: {}", e);
36
+ 1
37
+ }
38
+ }
39
+ }
40
+ Err(e) => {
41
+ eprintln!("Deserialization error: {}", e);
42
+ 1
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,45 @@
1
+ [package]
2
+ name = "tishlang_eval"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Tish tree-walk interpreter"
6
+
7
+ license-file = { workspace = true }
8
+ repository = { workspace = true }
9
+ [features]
10
+ default = []
11
+ # setTimeout / setInterval / clear* (standalone or with `import { … } from "tish:timers"`).
12
+ timers = []
13
+ http = [
14
+ "timers",
15
+ "tokio",
16
+ "reqwest",
17
+ "futures",
18
+ "tiny_http",
19
+ "tishlang_core/regex",
20
+ "dep:tishlang_runtime",
21
+ "tishlang_runtime/http",
22
+ # Interpreter + http means the runtime's `NativeFn` is `Arc<... + Send>`,
23
+ # so the interpreter's `CoreFn` variant must use the same shape.
24
+ "tishlang_core/send-values",
25
+ "tishlang_builtins/send-values",
26
+ ]
27
+ fs = []
28
+ process = []
29
+ regex = ["dep:fancy-regex", "tishlang_core/regex"]
30
+ tokio = ["dep:tokio"]
31
+ ws = ["dep:tishlang_runtime", "tishlang_runtime/ws"]
32
+
33
+ [dependencies]
34
+ ahash = "0.8.12"
35
+ rand = "0.10.1"
36
+ tishlang_ast = { path = "../tish_ast", version = ">=0.1" }
37
+ tishlang_builtins = { path = "../tish_builtins", version = ">=0.1" }
38
+ tishlang_parser = { path = "../tish_parser", version = ">=0.1" }
39
+ tishlang_core = { path = "../tish_core", version = ">=0.1" }
40
+ reqwest = { version = "0.13.2", default-features = false, features = ["rustls", "json", "stream"], optional = true }
41
+ futures = { version = "0.3.32", optional = true }
42
+ tiny_http = { version = "0.12.0", optional = true }
43
+ fancy-regex = { version = "0.17.0", optional = true }
44
+ tokio = { version = "1.50.0", features = ["rt-multi-thread", "time", "sync"], optional = true }
45
+ tishlang_runtime = { path = "../tish_runtime", version = ">=0.1", optional = true }