@tishlang/tish-format 1.0.12 → 2.0.1

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 (189) hide show
  1. package/Cargo.toml +51 -0
  2. package/LICENSE +13 -0
  3. package/bin/tish-format +0 -0
  4. package/crates/js_to_tish/Cargo.toml +11 -0
  5. package/crates/js_to_tish/README.md +18 -0
  6. package/crates/js_to_tish/src/error.rs +55 -0
  7. package/crates/js_to_tish/src/lib.rs +11 -0
  8. package/crates/js_to_tish/src/span_util.rs +35 -0
  9. package/crates/js_to_tish/src/transform/expr.rs +611 -0
  10. package/crates/js_to_tish/src/transform/stmt.rs +503 -0
  11. package/crates/js_to_tish/src/transform.rs +60 -0
  12. package/crates/tish/Cargo.toml +62 -0
  13. package/crates/tish/build.rs +21 -0
  14. package/crates/tish/src/cargo_native_registry.rs +32 -0
  15. package/crates/tish/src/cli_help.rs +576 -0
  16. package/crates/tish/src/main.rs +853 -0
  17. package/crates/tish/src/repl_completion.rs +199 -0
  18. package/crates/tish/tests/cargo_example_compile.rs +67 -0
  19. package/crates/tish/tests/error_source_location.rs +36 -0
  20. package/crates/tish/tests/fixtures/cargo_example_project/Cargo.toml +3 -0
  21. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/Cargo.toml +11 -0
  22. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/src/lib.rs +12 -0
  23. package/crates/tish/tests/fixtures/cargo_example_project/package.json +10 -0
  24. package/crates/tish/tests/fixtures/cargo_example_project/src/main.tish +3 -0
  25. package/crates/tish/tests/fixtures/runtime_error_location.tish +5 -0
  26. package/crates/tish/tests/fixtures/trycatch_runtime_errors.tish +15 -0
  27. package/crates/tish/tests/fixtures/tty_capability.tish +9 -0
  28. package/crates/tish/tests/integration_test.rs +1406 -0
  29. package/crates/tish/tests/run_optimize_stdout_parity.rs +50 -0
  30. package/crates/tish/tests/shortcircuit.rs +65 -0
  31. package/crates/tish/tests/trycatch_runtime_errors.rs +45 -0
  32. package/crates/tish/tests/tty_capability.rs +43 -0
  33. package/crates/tish_ast/Cargo.toml +9 -0
  34. package/crates/tish_ast/src/ast.rs +649 -0
  35. package/crates/tish_ast/src/lib.rs +5 -0
  36. package/crates/tish_build_utils/Cargo.toml +11 -0
  37. package/crates/tish_build_utils/src/lib.rs +577 -0
  38. package/crates/tish_builtins/Cargo.toml +22 -0
  39. package/crates/tish_builtins/src/array.rs +803 -0
  40. package/crates/tish_builtins/src/collections.rs +481 -0
  41. package/crates/tish_builtins/src/construct.rs +199 -0
  42. package/crates/tish_builtins/src/date.rs +538 -0
  43. package/crates/tish_builtins/src/globals.rs +293 -0
  44. package/crates/tish_builtins/src/helpers.rs +35 -0
  45. package/crates/tish_builtins/src/iterator.rs +129 -0
  46. package/crates/tish_builtins/src/lib.rs +21 -0
  47. package/crates/tish_builtins/src/math.rs +89 -0
  48. package/crates/tish_builtins/src/number.rs +96 -0
  49. package/crates/tish_builtins/src/object.rs +36 -0
  50. package/crates/tish_builtins/src/string.rs +646 -0
  51. package/crates/tish_builtins/src/symbol.rs +83 -0
  52. package/crates/tish_builtins/src/typedarrays.rs +298 -0
  53. package/crates/tish_bytecode/Cargo.toml +17 -0
  54. package/crates/tish_bytecode/src/chunk.rs +164 -0
  55. package/crates/tish_bytecode/src/compiler.rs +2604 -0
  56. package/crates/tish_bytecode/src/encoding.rs +102 -0
  57. package/crates/tish_bytecode/src/lib.rs +20 -0
  58. package/crates/tish_bytecode/src/opcode.rs +185 -0
  59. package/crates/tish_bytecode/src/peephole.rs +189 -0
  60. package/crates/tish_bytecode/src/serialize.rs +193 -0
  61. package/crates/tish_bytecode/tests/break_continue_bytecode.rs +44 -0
  62. package/crates/tish_bytecode/tests/constant_folding.rs +84 -0
  63. package/crates/tish_bytecode/tests/sort_optimization.rs +31 -0
  64. package/crates/tish_compile/Cargo.toml +27 -0
  65. package/crates/tish_compile/src/check.rs +774 -0
  66. package/crates/tish_compile/src/codegen.rs +7317 -0
  67. package/crates/tish_compile/src/infer.rs +1681 -0
  68. package/crates/tish_compile/src/lib.rs +206 -0
  69. package/crates/tish_compile/src/resolve.rs +1951 -0
  70. package/crates/tish_compile/src/types.rs +605 -0
  71. package/crates/tish_compile_js/Cargo.toml +18 -0
  72. package/crates/tish_compile_js/examples/jsx_vdom_smoke.tish +8 -0
  73. package/crates/tish_compile_js/src/codegen.rs +938 -0
  74. package/crates/tish_compile_js/src/error.rs +20 -0
  75. package/crates/tish_compile_js/src/lib.rs +26 -0
  76. package/crates/tish_compile_js/src/tests_jsx.rs +414 -0
  77. package/crates/tish_compiler_wasm/Cargo.toml +21 -0
  78. package/crates/tish_compiler_wasm/src/lib.rs +57 -0
  79. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +473 -0
  80. package/crates/tish_core/Cargo.toml +32 -0
  81. package/crates/tish_core/src/console_style.rs +170 -0
  82. package/crates/tish_core/src/json.rs +430 -0
  83. package/crates/tish_core/src/lib.rs +20 -0
  84. package/crates/tish_core/src/macros.rs +36 -0
  85. package/crates/tish_core/src/shape.rs +85 -0
  86. package/crates/tish_core/src/uri.rs +118 -0
  87. package/crates/tish_core/src/value.rs +1350 -0
  88. package/crates/tish_core/src/vmref.rs +183 -0
  89. package/crates/tish_cranelift/Cargo.toml +19 -0
  90. package/crates/tish_cranelift/src/lib.rs +43 -0
  91. package/crates/tish_cranelift/src/link.rs +130 -0
  92. package/crates/tish_cranelift/src/lower.rs +85 -0
  93. package/crates/tish_cranelift_runtime/Cargo.toml +26 -0
  94. package/crates/tish_cranelift_runtime/src/lib.rs +45 -0
  95. package/crates/tish_eval/Cargo.toml +51 -0
  96. package/crates/tish_eval/src/eval.rs +4265 -0
  97. package/crates/tish_eval/src/http.rs +191 -0
  98. package/crates/tish_eval/src/lib.rs +99 -0
  99. package/crates/tish_eval/src/natives.rs +551 -0
  100. package/crates/tish_eval/src/promise.rs +179 -0
  101. package/crates/tish_eval/src/regex.rs +299 -0
  102. package/crates/tish_eval/src/timers.rs +120 -0
  103. package/crates/tish_eval/src/value.rs +336 -0
  104. package/crates/tish_eval/src/value_convert.rs +117 -0
  105. package/crates/tish_ffi/Cargo.toml +26 -0
  106. package/crates/tish_ffi/src/lib.rs +518 -0
  107. package/crates/tish_ffi/tests/fixtures/testmod/Cargo.toml +18 -0
  108. package/crates/tish_ffi/tests/fixtures/testmod/src/lib.rs +46 -0
  109. package/crates/tish_ffi/tests/loader.rs +65 -0
  110. package/crates/tish_fmt/Cargo.toml +16 -0
  111. package/crates/tish_fmt/src/bin/tish-fmt.rs +41 -0
  112. package/crates/tish_fmt/src/lib.rs +2157 -0
  113. package/crates/tish_jsx_web/Cargo.toml +9 -0
  114. package/crates/tish_jsx_web/README.md +5 -0
  115. package/crates/tish_jsx_web/src/lib.rs +2 -0
  116. package/crates/tish_lexer/Cargo.toml +9 -0
  117. package/crates/tish_lexer/src/lib.rs +1104 -0
  118. package/crates/tish_lexer/src/token.rs +170 -0
  119. package/crates/tish_lint/Cargo.toml +18 -0
  120. package/crates/tish_lint/src/bin/tish-lint.rs +195 -0
  121. package/crates/tish_lint/src/lib.rs +281 -0
  122. package/crates/tish_llvm/Cargo.toml +13 -0
  123. package/crates/tish_llvm/src/lib.rs +115 -0
  124. package/crates/tish_lsp/Cargo.toml +25 -0
  125. package/crates/tish_lsp/README.md +26 -0
  126. package/crates/tish_lsp/src/builtin_goto.rs +362 -0
  127. package/crates/tish_lsp/src/import_goto.rs +564 -0
  128. package/crates/tish_lsp/src/main.rs +1459 -0
  129. package/crates/tish_native/Cargo.toml +16 -0
  130. package/crates/tish_native/src/build.rs +481 -0
  131. package/crates/tish_native/src/config.rs +48 -0
  132. package/crates/tish_native/src/lib.rs +416 -0
  133. package/crates/tish_opt/Cargo.toml +13 -0
  134. package/crates/tish_opt/src/lib.rs +1046 -0
  135. package/crates/tish_parser/Cargo.toml +11 -0
  136. package/crates/tish_parser/src/lib.rs +386 -0
  137. package/crates/tish_parser/src/parser.rs +2726 -0
  138. package/crates/tish_pg/Cargo.toml +34 -0
  139. package/crates/tish_pg/README.md +38 -0
  140. package/crates/tish_pg/src/error.rs +52 -0
  141. package/crates/tish_pg/src/lib.rs +955 -0
  142. package/crates/tish_resolve/Cargo.toml +13 -0
  143. package/crates/tish_resolve/src/lib.rs +3601 -0
  144. package/crates/tish_resolve/src/pos.rs +141 -0
  145. package/crates/tish_runtime/Cargo.toml +100 -0
  146. package/crates/tish_runtime/src/http.rs +1347 -0
  147. package/crates/tish_runtime/src/http_fetch.rs +492 -0
  148. package/crates/tish_runtime/src/http_hyper.rs +441 -0
  149. package/crates/tish_runtime/src/http_prefork.rs +189 -0
  150. package/crates/tish_runtime/src/lib.rs +1447 -0
  151. package/crates/tish_runtime/src/native_promise.rs +15 -0
  152. package/crates/tish_runtime/src/promise.rs +558 -0
  153. package/crates/tish_runtime/src/promise_io.rs +38 -0
  154. package/crates/tish_runtime/src/timers.rs +172 -0
  155. package/crates/tish_runtime/src/tty.rs +226 -0
  156. package/crates/tish_runtime/src/ws.rs +778 -0
  157. package/crates/tish_runtime/tests/fetch_readable_stream.rs +102 -0
  158. package/crates/tish_ui/Cargo.toml +17 -0
  159. package/crates/tish_ui/src/jsx.rs +692 -0
  160. package/crates/tish_ui/src/lib.rs +20 -0
  161. package/crates/tish_ui/src/runtime/hooks.rs +573 -0
  162. package/crates/tish_ui/src/runtime/mod.rs +183 -0
  163. package/crates/tish_vm/Cargo.toml +60 -0
  164. package/crates/tish_vm/src/jit.rs +1050 -0
  165. package/crates/tish_vm/src/lib.rs +41 -0
  166. package/crates/tish_vm/src/vm.rs +3536 -0
  167. package/crates/tish_vm/tests/concurrent_shared_state.rs +140 -0
  168. package/crates/tish_vm/tests/fixtures/or_string_cmd.tish +2 -0
  169. package/crates/tish_vm/tests/lexical_scope_declare.rs +34 -0
  170. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +150 -0
  171. package/crates/tish_wasm/Cargo.toml +15 -0
  172. package/crates/tish_wasm/src/lib.rs +428 -0
  173. package/crates/tish_wasm_runtime/Cargo.toml +37 -0
  174. package/crates/tish_wasm_runtime/src/gpu.rs +429 -0
  175. package/crates/tish_wasm_runtime/src/lib.rs +42 -0
  176. package/crates/tishlang_cargo_bindgen/Cargo.toml +26 -0
  177. package/crates/tishlang_cargo_bindgen/src/classify.rs +261 -0
  178. package/crates/tishlang_cargo_bindgen/src/discover.rs +125 -0
  179. package/crates/tishlang_cargo_bindgen/src/infer.rs +382 -0
  180. package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
  181. package/crates/tishlang_cargo_bindgen/src/main.rs +167 -0
  182. package/crates/tishlang_cargo_bindgen/src/metadata.rs +117 -0
  183. package/justfile +276 -0
  184. package/package.json +2 -2
  185. package/platform/darwin-arm64/tish-fmt +0 -0
  186. package/platform/darwin-x64/tish-fmt +0 -0
  187. package/platform/linux-arm64/tish-fmt +0 -0
  188. package/platform/linux-x64/tish-fmt +0 -0
  189. package/platform/win32-x64/tish-fmt.exe +0 -0
@@ -0,0 +1,503 @@
1
+ //! Convert OXC statements to Tish statements.
2
+
3
+ use std::sync::Arc;
4
+
5
+ use oxc::ast::ast::Statement as OxcStmt;
6
+ use oxc::semantic::Semantic;
7
+ use tishlang_ast::{Span, Statement};
8
+
9
+ use super::expr;
10
+ use crate::error::{ConvertError, ConvertErrorKind};
11
+ use crate::span_util;
12
+
13
+ type Ctx<'a> = (&'a Semantic<'a>, &'a str);
14
+
15
+ /// Convert OXC program body (statements) to Tish statements.
16
+ pub fn convert_statements(
17
+ body: &[OxcStmt<'_>],
18
+ semantic: &Semantic<'_>,
19
+ source: &str,
20
+ ) -> Result<Vec<Statement>, ConvertError> {
21
+ let ctx = (semantic, source);
22
+ body.iter().map(|s| convert_statement(s, &ctx)).collect()
23
+ }
24
+
25
+ fn convert_statement(stmt: &OxcStmt<'_>, ctx: &Ctx<'_>) -> Result<Statement, ConvertError> {
26
+ let span = span_util::oxc_span_to_tish(ctx.1, stmt);
27
+ match stmt {
28
+ OxcStmt::BlockStatement(b) => {
29
+ let statements = convert_statements(&b.body, ctx.0, ctx.1)?;
30
+ Ok(Statement::Block { statements, span })
31
+ }
32
+ OxcStmt::VariableDeclaration(v) => convert_var_decl(v, ctx, span),
33
+ OxcStmt::ExpressionStatement(e) => {
34
+ let expr = expr::convert_expr(&e.expression, ctx)?;
35
+ Ok(Statement::ExprStmt { expr, span })
36
+ }
37
+ OxcStmt::IfStatement(i) => {
38
+ let cond = expr::convert_expr(&i.test, ctx)?;
39
+ let then_branch = Box::new(convert_statement(&i.consequent, ctx)?);
40
+ let else_branch = i
41
+ .alternate
42
+ .as_ref()
43
+ .map(|a| convert_statement(a, ctx))
44
+ .transpose()?
45
+ .map(Box::new);
46
+ Ok(Statement::If {
47
+ cond,
48
+ then_branch,
49
+ else_branch,
50
+ span,
51
+ })
52
+ }
53
+ OxcStmt::ReturnStatement(r) => {
54
+ let value = r
55
+ .argument
56
+ .as_ref()
57
+ .map(|a| expr::convert_expr(a, ctx))
58
+ .transpose()?;
59
+ Ok(Statement::Return { value, span })
60
+ }
61
+ OxcStmt::BreakStatement(_) => Ok(Statement::Break { span }),
62
+ OxcStmt::ContinueStatement(_) => Ok(Statement::Continue { span }),
63
+ OxcStmt::WhileStatement(w) => {
64
+ let cond = expr::convert_expr(&w.test, ctx)?;
65
+ let body = Box::new(convert_statement(&w.body, ctx)?);
66
+ Ok(Statement::While { cond, body, span })
67
+ }
68
+ OxcStmt::DoWhileStatement(d) => {
69
+ let cond = expr::convert_expr(&d.test, ctx)?;
70
+ let body = Box::new(convert_statement(&d.body, ctx)?);
71
+ Ok(Statement::DoWhile { body, cond, span })
72
+ }
73
+ OxcStmt::ForStatement(f) => convert_for_statement(f, ctx, span),
74
+ OxcStmt::ForOfStatement(f) => convert_for_of_statement(f, ctx, span),
75
+ OxcStmt::SwitchStatement(s) => convert_switch_statement(s, ctx, span),
76
+ OxcStmt::ThrowStatement(t) => {
77
+ let value = expr::convert_expr(&t.argument, ctx)?;
78
+ Ok(Statement::Throw { value, span })
79
+ }
80
+ OxcStmt::TryStatement(t) => convert_try_statement(t, ctx, span),
81
+ OxcStmt::FunctionDeclaration(f) => convert_function_decl(f, ctx, span),
82
+ OxcStmt::EmptyStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
83
+ what: "empty statement".into(),
84
+ hint: None,
85
+ })),
86
+ OxcStmt::ForInStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
87
+ what: "for-in".into(),
88
+ hint: Some("Tish omits for-in".into()),
89
+ })),
90
+ OxcStmt::ClassDeclaration(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
91
+ what: "class".into(),
92
+ hint: Some("Tish does not support classes".into()),
93
+ })),
94
+ OxcStmt::WithStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
95
+ what: "with".into(),
96
+ hint: None,
97
+ })),
98
+ OxcStmt::DebuggerStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
99
+ what: "debugger".into(),
100
+ hint: None,
101
+ })),
102
+ OxcStmt::LabeledStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
103
+ what: "labeled statement".into(),
104
+ hint: None,
105
+ })),
106
+ OxcStmt::ImportDeclaration(i) => convert_import(i, ctx, span),
107
+ OxcStmt::ExportDefaultDeclaration(e) => convert_export_default(e, ctx, span),
108
+ OxcStmt::ExportNamedDeclaration(e) => convert_export_named(e, ctx, span),
109
+ OxcStmt::ExportAllDeclaration(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
110
+ what: "export *".into(),
111
+ hint: None,
112
+ })),
113
+ _ => Err(ConvertError::new(ConvertErrorKind::Unsupported {
114
+ what: format!("{:?}", std::mem::discriminant(stmt)),
115
+ hint: None,
116
+ })),
117
+ }
118
+ }
119
+
120
+ fn convert_declaration(
121
+ decl: &oxc::ast::ast::Declaration<'_>,
122
+ ctx: &Ctx<'_>,
123
+ ) -> Result<Statement, ConvertError> {
124
+ let span = span_util::oxc_span_to_tish(ctx.1, decl);
125
+ match decl {
126
+ oxc::ast::ast::Declaration::VariableDeclaration(v) => convert_var_decl(v, ctx, span),
127
+ oxc::ast::ast::Declaration::FunctionDeclaration(f) => convert_function_decl(f, ctx, span),
128
+ _ => Err(ConvertError::new(ConvertErrorKind::Unsupported {
129
+ what: format!("declaration: {:?}", std::mem::discriminant(decl)),
130
+ hint: None,
131
+ })),
132
+ }
133
+ }
134
+
135
+ fn convert_var_decl(
136
+ v: &oxc::ast::ast::VariableDeclaration<'_>,
137
+ ctx: &Ctx<'_>,
138
+ span: Span,
139
+ ) -> Result<Statement, ConvertError> {
140
+ let mutable = matches!(v.kind, oxc::ast::ast::VariableDeclarationKind::Let);
141
+ if v.declarations.len() == 1 {
142
+ let d = &v.declarations[0];
143
+ let id = &d.id;
144
+ let init = d
145
+ .init
146
+ .as_ref()
147
+ .map(|i| expr::convert_expr(i, ctx))
148
+ .transpose()?;
149
+ match id {
150
+ oxc::ast::ast::BindingPattern::BindingIdentifier(b) => {
151
+ let name: Arc<str> = Arc::from(b.name.as_str());
152
+ let name_span = span_util::oxc_span_to_tish(ctx.1, b.as_ref());
153
+ Ok(Statement::VarDecl {
154
+ name,
155
+ name_span,
156
+ mutable,
157
+ type_ann: None,
158
+ init,
159
+ span,
160
+ })
161
+ }
162
+ _ => {
163
+ let init = d
164
+ .init
165
+ .as_ref()
166
+ .map(|i| expr::convert_expr(i, ctx))
167
+ .transpose()?
168
+ .ok_or_else(|| {
169
+ ConvertError::new(ConvertErrorKind::Incompatible {
170
+ what: "destructuring declaration".into(),
171
+ reason: "initializer required".into(),
172
+ })
173
+ })?;
174
+ let pattern = expr::convert_destruct_pattern(id)?;
175
+ Ok(Statement::VarDeclDestructure {
176
+ pattern,
177
+ mutable,
178
+ init,
179
+ span,
180
+ })
181
+ }
182
+ }
183
+ } else {
184
+ Err(ConvertError::new(ConvertErrorKind::Incompatible {
185
+ what: "multi-declarator variable declaration".into(),
186
+ reason: "split into separate declarations".into(),
187
+ }))
188
+ }
189
+ }
190
+
191
+ fn convert_for_statement(
192
+ f: &oxc::ast::ast::ForStatement<'_>,
193
+ ctx: &Ctx<'_>,
194
+ span: Span,
195
+ ) -> Result<Statement, ConvertError> {
196
+ let init = f
197
+ .init
198
+ .as_ref()
199
+ .map(|i| match i {
200
+ oxc::ast::ast::ForStatementInit::VariableDeclaration(v) => {
201
+ convert_var_decl(v, ctx, span_util::stub_span()).map(Box::new)
202
+ }
203
+ _ => {
204
+ if let Some(e) = i.as_expression() {
205
+ expr::convert_expr(e, ctx).map(|expr| {
206
+ Box::new(Statement::ExprStmt {
207
+ expr,
208
+ span: span_util::stub_span(),
209
+ })
210
+ })
211
+ } else {
212
+ Err(ConvertError::new(ConvertErrorKind::Unsupported {
213
+ what: "for init".into(),
214
+ hint: None,
215
+ }))
216
+ }
217
+ }
218
+ })
219
+ .transpose()?;
220
+ let cond = f
221
+ .test
222
+ .as_ref()
223
+ .map(|e| expr::convert_expr(e, ctx))
224
+ .transpose()?;
225
+ let update = f
226
+ .update
227
+ .as_ref()
228
+ .map(|e| expr::convert_expr(e, ctx))
229
+ .transpose()?;
230
+ let body = Box::new(convert_statement(&f.body, ctx)?);
231
+ Ok(Statement::For {
232
+ init,
233
+ cond,
234
+ update,
235
+ body,
236
+ span,
237
+ })
238
+ }
239
+
240
+ fn convert_for_of_statement(
241
+ f: &oxc::ast::ast::ForOfStatement<'_>,
242
+ ctx: &Ctx<'_>,
243
+ span: Span,
244
+ ) -> Result<Statement, ConvertError> {
245
+ let (name, name_span) = match &f.left {
246
+ oxc::ast::ast::ForStatementLeft::VariableDeclaration(v) => {
247
+ if v.declarations.len() == 1 {
248
+ let d = &v.declarations[0];
249
+ match &d.id {
250
+ oxc::ast::ast::BindingPattern::BindingIdentifier(b) => (
251
+ b.name.as_str(),
252
+ span_util::oxc_span_to_tish(ctx.1, b.as_ref()),
253
+ ),
254
+ _ => {
255
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
256
+ what: "for-of with destructuring".into(),
257
+ reason: "use simple identifier".into(),
258
+ }))
259
+ }
260
+ }
261
+ } else {
262
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
263
+ what: "for-of with multiple bindings".into(),
264
+ reason: "not supported".into(),
265
+ }));
266
+ }
267
+ }
268
+ _ => {
269
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
270
+ what: "for-of (use variable declaration in left)".into(),
271
+ reason: "e.g. for (const x of arr)".into(),
272
+ }))
273
+ }
274
+ };
275
+ let iterable = expr::convert_expr(&f.right, ctx)?;
276
+ let body = Box::new(convert_statement(&f.body, ctx)?);
277
+ Ok(Statement::ForOf {
278
+ name: Arc::from(name),
279
+ name_span,
280
+ iterable,
281
+ body,
282
+ span,
283
+ })
284
+ }
285
+
286
+ fn convert_switch_statement(
287
+ s: &oxc::ast::ast::SwitchStatement<'_>,
288
+ ctx: &Ctx<'_>,
289
+ span: Span,
290
+ ) -> Result<Statement, ConvertError> {
291
+ let expr = expr::convert_expr(&s.discriminant, ctx)?;
292
+ let mut cases = Vec::new();
293
+ let mut default_body: Option<Vec<Statement>> = None;
294
+ for c in &s.cases {
295
+ let stmts = convert_statements(&c.consequent, ctx.0, ctx.1)?;
296
+ match &c.test {
297
+ Some(t) => cases.push((Some(expr::convert_expr(t, ctx)?), stmts)),
298
+ None => default_body = Some(stmts),
299
+ }
300
+ }
301
+ Ok(Statement::Switch {
302
+ expr,
303
+ cases,
304
+ default_body,
305
+ span,
306
+ })
307
+ }
308
+
309
+ fn convert_try_statement(
310
+ t: &oxc::ast::ast::TryStatement<'_>,
311
+ ctx: &Ctx<'_>,
312
+ span: Span,
313
+ ) -> Result<Statement, ConvertError> {
314
+ // TryStatement.block is BlockStatement; convert its body to Statement::Block
315
+ let body_stmts = convert_statements(&t.block.body, ctx.0, ctx.1)?;
316
+ let body = Box::new(Statement::Block {
317
+ statements: body_stmts,
318
+ span: span_util::oxc_span_to_tish(ctx.1, &*t.block),
319
+ });
320
+ let (catch_param, catch_param_span, catch_body) = match &t.handler {
321
+ Some(h) => {
322
+ let (param, pspan) = h
323
+ .param
324
+ .as_ref()
325
+ .and_then(|cp: &oxc::ast::ast::CatchParameter<'_>| {
326
+ if let oxc::ast::ast::BindingPattern::BindingIdentifier(b) = &cp.pattern {
327
+ Some((
328
+ Arc::from(b.name.as_str()),
329
+ span_util::oxc_span_to_tish(ctx.1, b.as_ref()),
330
+ ))
331
+ } else {
332
+ None
333
+ }
334
+ })
335
+ .map_or((None, None), |(n, s)| (Some(n), Some(s)));
336
+ let catch_stmts = convert_statements(&h.body.body, ctx.0, ctx.1)?;
337
+ let cb = Box::new(Statement::Block {
338
+ statements: catch_stmts,
339
+ span: span_util::oxc_span_to_tish(ctx.1, &*h.body),
340
+ });
341
+ (param, pspan, Some(cb))
342
+ }
343
+ None => (None, None, None),
344
+ };
345
+ let finally_body = t
346
+ .finalizer
347
+ .as_ref()
348
+ .map(|f| {
349
+ let stmts = convert_statements(&f.body, ctx.0, ctx.1)?;
350
+ Ok(Box::new(Statement::Block {
351
+ statements: stmts,
352
+ span: span_util::oxc_span_to_tish(ctx.1, &**f),
353
+ }))
354
+ })
355
+ .transpose()?;
356
+ Ok(Statement::Try {
357
+ body,
358
+ catch_param,
359
+ catch_param_span,
360
+ catch_body,
361
+ finally_body,
362
+ span,
363
+ })
364
+ }
365
+
366
+ fn convert_function_decl(
367
+ f: &oxc::ast::ast::Function<'_>,
368
+ ctx: &Ctx<'_>,
369
+ span: Span,
370
+ ) -> Result<Statement, ConvertError> {
371
+ let async_ = f.r#async;
372
+ let name: Arc<str> =
373
+ f.id.as_ref()
374
+ .map(|id| Arc::from(id.name.as_str()))
375
+ .unwrap_or_else(|| Arc::from(""));
376
+ let name_span =
377
+ f.id.as_ref()
378
+ .map(|id| span_util::oxc_span_to_tish(ctx.1, id))
379
+ .unwrap_or_else(span_util::stub_span);
380
+ let (params, rest_param) = expr::convert_params(&f.params, ctx)?;
381
+ let body = match &f.body {
382
+ Some(fb) => {
383
+ let stmts = convert_statements(&fb.statements, ctx.0, ctx.1)?;
384
+ Box::new(Statement::Block {
385
+ statements: stmts,
386
+ span: span_util::oxc_span_to_tish(ctx.1, fb.as_ref()),
387
+ })
388
+ }
389
+ None => {
390
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
391
+ what: "function body".into(),
392
+ reason: "expected block".into(),
393
+ }))
394
+ }
395
+ };
396
+ Ok(Statement::FunDecl {
397
+ async_,
398
+ name,
399
+ name_span,
400
+ params,
401
+ rest_param,
402
+ return_type: None,
403
+ body,
404
+ span,
405
+ })
406
+ }
407
+
408
+ fn convert_import(
409
+ i: &oxc::ast::ast::ImportDeclaration<'_>,
410
+ ctx: &Ctx<'_>,
411
+ span: Span,
412
+ ) -> Result<Statement, ConvertError> {
413
+ let from: Arc<str> = Arc::from(i.source.value.as_str());
414
+ let mut specifiers = Vec::new();
415
+ if let Some(specs) = &i.specifiers {
416
+ for s in specs.iter() {
417
+ match s {
418
+ oxc::ast::ast::ImportDeclarationSpecifier::ImportSpecifier(is) => {
419
+ let imported_name = is.imported.name().as_str();
420
+ let local_name = is.local.name.as_str();
421
+ let name_span = crate::span_util::oxc_span_to_tish(ctx.1, &is.imported);
422
+ let (alias, alias_span) = if imported_name == local_name {
423
+ (None, None)
424
+ } else {
425
+ (
426
+ Some(Arc::from(local_name)),
427
+ Some(crate::span_util::oxc_span_to_tish(ctx.1, &is.local)),
428
+ )
429
+ };
430
+ specifiers.push(tishlang_ast::ImportSpecifier::Named {
431
+ name: Arc::from(imported_name),
432
+ name_span,
433
+ alias,
434
+ alias_span,
435
+ });
436
+ }
437
+ oxc::ast::ast::ImportDeclarationSpecifier::ImportDefaultSpecifier(ds) => {
438
+ let name_span = crate::span_util::oxc_span_to_tish(ctx.1, &ds.local);
439
+ specifiers.push(tishlang_ast::ImportSpecifier::Default {
440
+ name: Arc::from(ds.local.name.as_str()),
441
+ name_span,
442
+ });
443
+ }
444
+ oxc::ast::ast::ImportDeclarationSpecifier::ImportNamespaceSpecifier(ns) => {
445
+ let name_span = crate::span_util::oxc_span_to_tish(ctx.1, &ns.local);
446
+ specifiers.push(tishlang_ast::ImportSpecifier::Namespace {
447
+ name: Arc::from(ns.local.name.as_str()),
448
+ name_span,
449
+ });
450
+ }
451
+ }
452
+ }
453
+ }
454
+ Ok(Statement::Import {
455
+ specifiers,
456
+ from,
457
+ span,
458
+ })
459
+ }
460
+
461
+ fn convert_export_default(
462
+ e: &oxc::ast::ast::ExportDefaultDeclaration<'_>,
463
+ ctx: &Ctx<'_>,
464
+ span: Span,
465
+ ) -> Result<Statement, ConvertError> {
466
+ let declaration = if let Some(expr) = e.declaration.as_expression() {
467
+ let expr = expr::convert_expr(expr, ctx)?;
468
+ tishlang_ast::ExportDeclaration::Default(expr)
469
+ } else if let oxc::ast::ast::ExportDefaultDeclarationKind::FunctionDeclaration(f) =
470
+ &e.declaration
471
+ {
472
+ let stmt = convert_function_decl(f.as_ref(), ctx, span_util::stub_span())?;
473
+ tishlang_ast::ExportDeclaration::Named(Box::new(stmt))
474
+ } else {
475
+ return Err(ConvertError::new(ConvertErrorKind::Unsupported {
476
+ what: "export default (this form)".into(),
477
+ hint: None,
478
+ }));
479
+ };
480
+ Ok(Statement::Export {
481
+ declaration: Box::new(declaration),
482
+ span,
483
+ })
484
+ }
485
+
486
+ fn convert_export_named(
487
+ e: &oxc::ast::ast::ExportNamedDeclaration<'_>,
488
+ ctx: &Ctx<'_>,
489
+ span: Span,
490
+ ) -> Result<Statement, ConvertError> {
491
+ if let Some(decl) = &e.declaration {
492
+ let stmt = convert_declaration(decl, ctx)?;
493
+ Ok(Statement::Export {
494
+ declaration: Box::new(tishlang_ast::ExportDeclaration::Named(Box::new(stmt))),
495
+ span,
496
+ })
497
+ } else {
498
+ Err(ConvertError::new(ConvertErrorKind::Unsupported {
499
+ what: "export { ... } (re-exports)".into(),
500
+ hint: None,
501
+ }))
502
+ }
503
+ }
@@ -0,0 +1,60 @@
1
+ //! Convert OXC AST (with semantic info) to Tish AST.
2
+
3
+ mod expr;
4
+ mod stmt;
5
+
6
+ use oxc::allocator::Allocator;
7
+ use oxc::parser::Parser;
8
+ use oxc::semantic::SemanticBuilder;
9
+ use oxc::span::SourceType;
10
+ use tishlang_ast::Program;
11
+
12
+ use crate::error::{ConvertError, ConvertErrorKind};
13
+ use crate::transform::stmt::convert_statements;
14
+
15
+ /// Convert JavaScript source to Tish AST.
16
+ ///
17
+ /// Performs parse, semantic analysis, normalization (var/function hoisting),
18
+ /// and transformation to Tish AST.
19
+ pub fn convert(js_source: &str) -> Result<Program, ConvertError> {
20
+ let allocator = Allocator::default();
21
+ let source_type = SourceType::from_path("script.js").unwrap();
22
+ let parser_ret = Parser::new(&allocator, js_source, source_type).parse();
23
+
24
+ if parser_ret.panicked {
25
+ let msg = parser_ret
26
+ .errors
27
+ .iter()
28
+ .map(|e| format!("{e:?}"))
29
+ .collect::<Vec<_>>()
30
+ .join("; ");
31
+ return Err(ConvertError::new(ConvertErrorKind::Parse(msg)));
32
+ }
33
+ if !parser_ret.errors.is_empty() {
34
+ let msg = parser_ret
35
+ .errors
36
+ .into_iter()
37
+ .map(|e| format!("{e:?}"))
38
+ .collect::<Vec<_>>()
39
+ .join("; ");
40
+ return Err(ConvertError::new(ConvertErrorKind::Parse(msg)));
41
+ }
42
+
43
+ let program = parser_ret.program;
44
+ let semantic_ret = SemanticBuilder::new()
45
+ .with_check_syntax_error(true)
46
+ .build(&program);
47
+
48
+ if !semantic_ret.errors.is_empty() {
49
+ let msg = semantic_ret
50
+ .errors
51
+ .into_iter()
52
+ .map(|e| format!("{e:?}"))
53
+ .collect::<Vec<_>>()
54
+ .join("; ");
55
+ return Err(ConvertError::new(ConvertErrorKind::Semantic(msg)));
56
+ }
57
+
58
+ let statements = convert_statements(&program.body, &semantic_ret.semantic, js_source)?;
59
+ Ok(Program { statements })
60
+ }
@@ -0,0 +1,62 @@
1
+ [package]
2
+ name = "tishlang"
3
+ version = "0.0.0-dev"
4
+ edition = "2021"
5
+ description = "Tish CLI - run, REPL, compile to native"
6
+ license-file = { workspace = true }
7
+ repository = { workspace = true }
8
+
9
+ [[bin]]
10
+ name = "tish"
11
+ path = "src/main.rs"
12
+
13
+ [features]
14
+ # The published `tish` CLI always includes every optional runtime (http, timers, fs, process, regex, ws).
15
+ # Use `cargo build -p tishlang --no-default-features` when you need a locked-down toolchain
16
+ # (see workspace `justfile`). `tish run --feature …` / `tish build --feature …` gate what runs
17
+ # or what gets linked into a *native output* binary — they are not the primary way to ship a
18
+ # “full” vs “empty” CLI.
19
+ default = ["full", "fast-alloc"]
20
+ # Alias: same dependency edges as `default` (kept for `--features full` in CI and docs).
21
+ # Includes `pg` so `tish run` can resolve `import … from '@tishlang/pg'` (`cargo:tish_pg`) on the bytecode VM.
22
+ full = ["http", "fs", "process", "regex", "ws", "timers", "tty", "pg"]
23
+ # Fast allocator (mimalloc) as the process `#[global_allocator]`. tish's object/array/string workloads
24
+ # are allocation-bound (a sampling profile of object-heavy code spends ~14%+ in system malloc/free);
25
+ # mimalloc is markedly faster for the many-small-allocations pattern — the same reason JSC ships bmalloc.
26
+ # Semantically transparent (just a faster malloc); `--no-default-features` drops it for the system allocator.
27
+ fast-alloc = ["dep:mimalloc"]
28
+ # Opt-out: build without Postgres (`cargo build -p tishlang --no-default-features --features http,...`).
29
+ pg = ["dep:tishlang_pg"]
30
+ # Individual capability flags
31
+ http = ["tishlang_eval/http", "tishlang_runtime/http", "tishlang_compile/http", "tishlang_vm/http"]
32
+ timers = ["tishlang_eval/timers", "tishlang_compile/timers", "tishlang_vm/timers"]
33
+ fs = ["tishlang_eval/fs", "tishlang_runtime/fs", "tishlang_compile/fs", "tishlang_vm/fs"]
34
+ process = ["tishlang_eval/process", "tishlang_runtime/process", "tishlang_compile/process", "tishlang_vm/process"]
35
+ regex = ["tishlang_eval/regex", "tishlang_runtime/regex", "tishlang_compile/regex", "tishlang_vm/regex"]
36
+ ws = ["tishlang_eval/ws", "tishlang_runtime/ws", "tishlang_compile/ws", "tishlang_vm/ws"]
37
+ tty = ["tishlang_eval/tty", "tishlang_runtime/tty", "tishlang_compile/tty", "tishlang_vm/tty"]
38
+ # GPU compute — Apple Silicon only
39
+ [dependencies]
40
+ rustyline = { version = "17", features = ["with-file-history"] }
41
+ tishlang_lexer = { path = "../tish_lexer", version = ">=0.1" }
42
+ tishlang_ast = { path = "../tish_ast", version = ">=0.1" }
43
+ tishlang_parser = { path = "../tish_parser", version = ">=0.1" }
44
+ tishlang_eval = { path = "../tish_eval", version = ">=0.1" }
45
+ tishlang_compile = { path = "../tish_compile", version = ">=0.1" }
46
+ tishlang_compile_js = { path = "../tish_compile_js", version = ">=0.1" }
47
+ tishlang_bytecode = { path = "../tish_bytecode", version = ">=0.1" }
48
+ tishlang_opt = { path = "../tish_opt", version = ">=0.1" }
49
+ tishlang_vm = { path = "../tish_vm", version = ">=0.1" }
50
+ tishlang_ffi = { path = "../tish_ffi", version = ">=0.1" }
51
+ tishlang_native = { path = "../tish_native", version = ">=0.1" }
52
+ tishlang_llvm = { path = "../tish_llvm", version = ">=0.1" }
53
+ tishlang_wasm = { path = "../tish_wasm", version = ">=0.1" }
54
+ tishlang_runtime = { path = "../tish_runtime", version = ">=0.1" }
55
+ tishlang_core = { path = "../tish_core", version = ">=0.1" }
56
+ tishlang_js_to_tish = { path = "../js_to_tish", version = ">=0.1" }
57
+ clap = { version = "4.6.0", features = ["derive", "color"] }
58
+ tishlang_pg = { path = "../tish_pg", version = ">=0.1", optional = true }
59
+ mimalloc = { version = "0.1", optional = true }
60
+
61
+ [dev-dependencies]
62
+ rayon = "1.11"
@@ -0,0 +1,21 @@
1
+ //! Export the `tish_value_*` C-ABI accessors (from `tishlang_ffi`) in the `tish` binary's dynamic
2
+ //! symbol table, so a `dlopen`'d native extension (`ffi:`) can resolve them at load time. This is
3
+ //! the **decoupled** FFI model: the extension declares the accessors `extern "C"` and does NOT link
4
+ //! `tish_core`, so there is a single value representation and no host/extension layout matching.
5
+ //! Without this flag the host's accessor symbols aren't visible to the loaded library.
6
+
7
+ fn main() {
8
+ let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
9
+ match target_os.as_str() {
10
+ // macOS/iOS: export all global symbols (so the two-level-namespace binary exposes them).
11
+ "macos" | "ios" => {
12
+ println!("cargo:rustc-link-arg-bins=-Wl,-export_dynamic");
13
+ }
14
+ // Windows PE export tables work differently; the host-export FFI model isn't wired there yet.
15
+ "windows" => {}
16
+ // Linux/BSD: -rdynamic puts all symbols in the dynamic table.
17
+ _ => {
18
+ println!("cargo:rustc-link-arg-bins=-rdynamic");
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,32 @@
1
+ //! Registers `cargo:*` Rust shims on the bytecode VM (`tish run`, REPL).
2
+ //!
3
+ //! Native `tish build` outputs register their own crates at link time; the
4
+ //! interpreter path must populate [`tishlang_vm::Vm::register_native_module`].
5
+
6
+ #[cfg(feature = "pg")]
7
+ pub(crate) fn register_bytecode_native_modules(vm: &mut tishlang_vm::Vm) {
8
+ use std::sync::Arc;
9
+ use tishlang_core::{ObjectMap, Value};
10
+
11
+ let mut om = ObjectMap::with_capacity(8);
12
+ om.insert(
13
+ Arc::from("per_worker_client"),
14
+ Value::native(tishlang_pg::per_worker_client),
15
+ );
16
+ om.insert(Arc::from("connect"), Value::native(tishlang_pg::connect));
17
+ om.insert(Arc::from("prepare"), Value::native(tishlang_pg::prepare));
18
+ om.insert(
19
+ Arc::from("query_prepared"),
20
+ Value::native(tishlang_pg::query_prepared),
21
+ );
22
+ om.insert(
23
+ Arc::from("query_all"),
24
+ Value::native(tishlang_pg::query_all),
25
+ );
26
+ om.insert(Arc::from("migrate"), Value::native(tishlang_pg::migrate));
27
+ om.insert(Arc::from("close"), Value::native(tishlang_pg::close));
28
+ vm.register_native_module("cargo:tish_pg", om);
29
+ }
30
+
31
+ #[cfg(not(feature = "pg"))]
32
+ pub(crate) fn register_bytecode_native_modules(_vm: &mut tishlang_vm::Vm) {}