@tishlang/tish 1.0.7 → 1.0.11

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 (127) hide show
  1. package/Cargo.toml +43 -0
  2. package/LICENSE +13 -0
  3. package/README.md +66 -0
  4. package/crates/js_to_tish/Cargo.toml +9 -0
  5. package/crates/js_to_tish/README.md +18 -0
  6. package/crates/js_to_tish/src/error.rs +61 -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 +608 -0
  10. package/crates/js_to_tish/src/transform/stmt.rs +474 -0
  11. package/crates/js_to_tish/src/transform.rs +60 -0
  12. package/crates/tish/Cargo.toml +44 -0
  13. package/crates/tish/src/main.rs +585 -0
  14. package/crates/tish/src/repl_completion.rs +200 -0
  15. package/crates/tish/tests/integration_test.rs +726 -0
  16. package/crates/tish_ast/Cargo.toml +7 -0
  17. package/crates/tish_ast/src/ast.rs +494 -0
  18. package/crates/tish_ast/src/lib.rs +5 -0
  19. package/crates/tish_build_utils/Cargo.toml +5 -0
  20. package/crates/tish_build_utils/src/lib.rs +175 -0
  21. package/crates/tish_builtins/Cargo.toml +12 -0
  22. package/crates/tish_builtins/src/array.rs +410 -0
  23. package/crates/tish_builtins/src/globals.rs +197 -0
  24. package/crates/tish_builtins/src/helpers.rs +38 -0
  25. package/crates/tish_builtins/src/lib.rs +14 -0
  26. package/crates/tish_builtins/src/math.rs +80 -0
  27. package/crates/tish_builtins/src/object.rs +36 -0
  28. package/crates/tish_builtins/src/string.rs +253 -0
  29. package/crates/tish_bytecode/Cargo.toml +15 -0
  30. package/crates/tish_bytecode/src/chunk.rs +97 -0
  31. package/crates/tish_bytecode/src/compiler.rs +1361 -0
  32. package/crates/tish_bytecode/src/encoding.rs +100 -0
  33. package/crates/tish_bytecode/src/lib.rs +19 -0
  34. package/crates/tish_bytecode/src/opcode.rs +110 -0
  35. package/crates/tish_bytecode/src/peephole.rs +159 -0
  36. package/crates/tish_bytecode/src/serialize.rs +163 -0
  37. package/crates/tish_bytecode/tests/constant_folding.rs +84 -0
  38. package/crates/tish_bytecode/tests/shortcircuit.rs +49 -0
  39. package/crates/tish_bytecode/tests/sort_optimization.rs +31 -0
  40. package/crates/tish_compile/Cargo.toml +21 -0
  41. package/crates/tish_compile/src/codegen.rs +3316 -0
  42. package/crates/tish_compile/src/lib.rs +71 -0
  43. package/crates/tish_compile/src/resolve.rs +631 -0
  44. package/crates/tish_compile/src/types.rs +304 -0
  45. package/crates/tish_compile_js/Cargo.toml +16 -0
  46. package/crates/tish_compile_js/examples/jsx_vdom_smoke.tish +8 -0
  47. package/crates/tish_compile_js/src/codegen.rs +794 -0
  48. package/crates/tish_compile_js/src/error.rs +20 -0
  49. package/crates/tish_compile_js/src/js_intrinsics.rs +82 -0
  50. package/crates/tish_compile_js/src/lib.rs +27 -0
  51. package/crates/tish_compile_js/src/tests_jsx.rs +32 -0
  52. package/crates/tish_compiler_wasm/Cargo.toml +19 -0
  53. package/crates/tish_compiler_wasm/src/lib.rs +55 -0
  54. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +462 -0
  55. package/crates/tish_core/Cargo.toml +11 -0
  56. package/crates/tish_core/src/console_style.rs +128 -0
  57. package/crates/tish_core/src/json.rs +327 -0
  58. package/crates/tish_core/src/lib.rs +15 -0
  59. package/crates/tish_core/src/macros.rs +37 -0
  60. package/crates/tish_core/src/uri.rs +115 -0
  61. package/crates/tish_core/src/value.rs +376 -0
  62. package/crates/tish_cranelift/Cargo.toml +17 -0
  63. package/crates/tish_cranelift/src/lib.rs +41 -0
  64. package/crates/tish_cranelift/src/link.rs +120 -0
  65. package/crates/tish_cranelift/src/lower.rs +77 -0
  66. package/crates/tish_cranelift_runtime/Cargo.toml +19 -0
  67. package/crates/tish_cranelift_runtime/src/lib.rs +43 -0
  68. package/crates/tish_eval/Cargo.toml +26 -0
  69. package/crates/tish_eval/src/eval.rs +3205 -0
  70. package/crates/tish_eval/src/http.rs +122 -0
  71. package/crates/tish_eval/src/lib.rs +59 -0
  72. package/crates/tish_eval/src/natives.rs +301 -0
  73. package/crates/tish_eval/src/promise.rs +173 -0
  74. package/crates/tish_eval/src/regex.rs +298 -0
  75. package/crates/tish_eval/src/timers.rs +111 -0
  76. package/crates/tish_eval/src/value.rs +224 -0
  77. package/crates/tish_eval/src/value_convert.rs +85 -0
  78. package/crates/tish_fmt/Cargo.toml +16 -0
  79. package/crates/tish_fmt/src/bin/tish-fmt.rs +41 -0
  80. package/crates/tish_fmt/src/lib.rs +884 -0
  81. package/crates/tish_jsx_web/Cargo.toml +7 -0
  82. package/crates/tish_jsx_web/README.md +18 -0
  83. package/crates/tish_jsx_web/src/lib.rs +157 -0
  84. package/crates/tish_jsx_web/vendor/Lattish.tish +347 -0
  85. package/crates/tish_lexer/Cargo.toml +7 -0
  86. package/crates/tish_lexer/src/lib.rs +430 -0
  87. package/crates/tish_lexer/src/token.rs +155 -0
  88. package/crates/tish_lint/Cargo.toml +17 -0
  89. package/crates/tish_lint/src/bin/tish-lint.rs +77 -0
  90. package/crates/tish_lint/src/lib.rs +278 -0
  91. package/crates/tish_llvm/Cargo.toml +11 -0
  92. package/crates/tish_llvm/src/lib.rs +106 -0
  93. package/crates/tish_lsp/Cargo.toml +22 -0
  94. package/crates/tish_lsp/README.md +26 -0
  95. package/crates/tish_lsp/src/main.rs +615 -0
  96. package/crates/tish_native/Cargo.toml +14 -0
  97. package/crates/tish_native/src/build.rs +102 -0
  98. package/crates/tish_native/src/lib.rs +237 -0
  99. package/crates/tish_opt/Cargo.toml +11 -0
  100. package/crates/tish_opt/src/lib.rs +896 -0
  101. package/crates/tish_parser/Cargo.toml +9 -0
  102. package/crates/tish_parser/src/lib.rs +123 -0
  103. package/crates/tish_parser/src/parser.rs +1714 -0
  104. package/crates/tish_runtime/Cargo.toml +26 -0
  105. package/crates/tish_runtime/src/http.rs +308 -0
  106. package/crates/tish_runtime/src/http_fetch.rs +453 -0
  107. package/crates/tish_runtime/src/lib.rs +1004 -0
  108. package/crates/tish_runtime/src/native_promise.rs +26 -0
  109. package/crates/tish_runtime/src/promise.rs +77 -0
  110. package/crates/tish_runtime/src/promise_io.rs +41 -0
  111. package/crates/tish_runtime/src/timers.rs +125 -0
  112. package/crates/tish_runtime/src/ws.rs +725 -0
  113. package/crates/tish_runtime/tests/fetch_readable_stream.rs +99 -0
  114. package/crates/tish_vm/Cargo.toml +31 -0
  115. package/crates/tish_vm/src/lib.rs +39 -0
  116. package/crates/tish_vm/src/vm.rs +1399 -0
  117. package/crates/tish_wasm/Cargo.toml +13 -0
  118. package/crates/tish_wasm/src/lib.rs +358 -0
  119. package/crates/tish_wasm_runtime/Cargo.toml +25 -0
  120. package/crates/tish_wasm_runtime/src/lib.rs +36 -0
  121. package/justfile +260 -0
  122. package/package.json +8 -3
  123. package/platform/darwin-arm64/tish +0 -0
  124. package/platform/darwin-x64/tish +0 -0
  125. package/platform/linux-arm64/tish +0 -0
  126. package/platform/linux-x64/tish +0 -0
  127. package/platform/win32-x64/tish.exe +0 -0
@@ -0,0 +1,474 @@
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 tish_ast::{Statement, Span};
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()
23
+ .map(|s| convert_statement(s, &ctx))
24
+ .collect()
25
+ }
26
+
27
+ fn convert_statement(stmt: &OxcStmt<'_>, ctx: &Ctx<'_>) -> Result<Statement, ConvertError> {
28
+ let span = span_util::oxc_span_to_tish(ctx.1, stmt);
29
+ match stmt {
30
+ OxcStmt::BlockStatement(b) => {
31
+ let statements = convert_statements(&b.body, ctx.0, ctx.1)?;
32
+ Ok(Statement::Block {
33
+ statements,
34
+ span,
35
+ })
36
+ }
37
+ OxcStmt::VariableDeclaration(v) => convert_var_decl(v, ctx, span),
38
+ OxcStmt::ExpressionStatement(e) => {
39
+ let expr = expr::convert_expr(&e.expression, ctx)?;
40
+ Ok(Statement::ExprStmt { expr, span })
41
+ }
42
+ OxcStmt::IfStatement(i) => {
43
+ let cond = expr::convert_expr(&i.test, ctx)?;
44
+ let then_branch = Box::new(convert_statement(&i.consequent, ctx)?);
45
+ let else_branch = i
46
+ .alternate
47
+ .as_ref()
48
+ .map(|a| convert_statement(a, ctx))
49
+ .transpose()?
50
+ .map(Box::new);
51
+ Ok(Statement::If {
52
+ cond,
53
+ then_branch,
54
+ else_branch,
55
+ span,
56
+ })
57
+ }
58
+ OxcStmt::ReturnStatement(r) => {
59
+ let value = r
60
+ .argument
61
+ .as_ref()
62
+ .map(|a| expr::convert_expr(a, ctx))
63
+ .transpose()?;
64
+ Ok(Statement::Return { value, span })
65
+ }
66
+ OxcStmt::BreakStatement(_) => Ok(Statement::Break { span }),
67
+ OxcStmt::ContinueStatement(_) => Ok(Statement::Continue { span }),
68
+ OxcStmt::WhileStatement(w) => {
69
+ let cond = expr::convert_expr(&w.test, ctx)?;
70
+ let body = Box::new(convert_statement(&w.body, ctx)?);
71
+ Ok(Statement::While { cond, body, span })
72
+ }
73
+ OxcStmt::DoWhileStatement(d) => {
74
+ let cond = expr::convert_expr(&d.test, ctx)?;
75
+ let body = Box::new(convert_statement(&d.body, ctx)?);
76
+ Ok(Statement::DoWhile { body, cond, span })
77
+ }
78
+ OxcStmt::ForStatement(f) => convert_for_statement(f, ctx, span),
79
+ OxcStmt::ForOfStatement(f) => convert_for_of_statement(f, ctx, span),
80
+ OxcStmt::SwitchStatement(s) => convert_switch_statement(s, ctx, span),
81
+ OxcStmt::ThrowStatement(t) => {
82
+ let value = expr::convert_expr(&t.argument, ctx)?;
83
+ Ok(Statement::Throw { value, span })
84
+ }
85
+ OxcStmt::TryStatement(t) => convert_try_statement(t, ctx, span),
86
+ OxcStmt::FunctionDeclaration(f) => convert_function_decl(f, ctx, span),
87
+ OxcStmt::EmptyStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
88
+ what: "empty statement".into(),
89
+ hint: None,
90
+ })),
91
+ OxcStmt::ForInStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
92
+ what: "for-in".into(),
93
+ hint: Some("Tish omits for-in".into()),
94
+ })),
95
+ OxcStmt::ClassDeclaration(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
96
+ what: "class".into(),
97
+ hint: Some("Tish does not support classes".into()),
98
+ })),
99
+ OxcStmt::WithStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
100
+ what: "with".into(),
101
+ hint: None,
102
+ })),
103
+ OxcStmt::DebuggerStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
104
+ what: "debugger".into(),
105
+ hint: None,
106
+ })),
107
+ OxcStmt::LabeledStatement(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
108
+ what: "labeled statement".into(),
109
+ hint: None,
110
+ })),
111
+ OxcStmt::ImportDeclaration(i) => convert_import(i, ctx, span),
112
+ OxcStmt::ExportDefaultDeclaration(e) => convert_export_default(e, ctx, span),
113
+ OxcStmt::ExportNamedDeclaration(e) => convert_export_named(e, ctx, span),
114
+ OxcStmt::ExportAllDeclaration(_) => Err(ConvertError::new(ConvertErrorKind::Unsupported {
115
+ what: "export *".into(),
116
+ hint: None,
117
+ })),
118
+ _ => Err(ConvertError::new(ConvertErrorKind::Unsupported {
119
+ what: format!("{:?}", std::mem::discriminant(stmt)),
120
+ hint: None,
121
+ })),
122
+ }
123
+ }
124
+
125
+ fn convert_declaration(
126
+ decl: &oxc::ast::ast::Declaration<'_>,
127
+ ctx: &Ctx<'_>,
128
+ ) -> Result<Statement, ConvertError> {
129
+ let span = span_util::oxc_span_to_tish(ctx.1, decl);
130
+ match decl {
131
+ oxc::ast::ast::Declaration::VariableDeclaration(v) => convert_var_decl(v, ctx, span),
132
+ oxc::ast::ast::Declaration::FunctionDeclaration(f) => convert_function_decl(f, ctx, span),
133
+ _ => Err(ConvertError::new(ConvertErrorKind::Unsupported {
134
+ what: format!("declaration: {:?}", std::mem::discriminant(decl)),
135
+ hint: None,
136
+ })),
137
+ }
138
+ }
139
+
140
+ fn convert_var_decl(
141
+ v: &oxc::ast::ast::VariableDeclaration<'_>,
142
+ ctx: &Ctx<'_>,
143
+ span: Span,
144
+ ) -> Result<Statement, ConvertError> {
145
+ let mutable = matches!(v.kind, oxc::ast::ast::VariableDeclarationKind::Let);
146
+ if v.declarations.len() == 1 {
147
+ let d = &v.declarations[0];
148
+ let id = &d.id;
149
+ let init = d.init.as_ref().map(|i| expr::convert_expr(i, ctx)).transpose()?;
150
+ match id {
151
+ oxc::ast::ast::BindingPattern::BindingIdentifier(b) => {
152
+ let name: Arc<str> = Arc::from(b.name.as_str());
153
+ Ok(Statement::VarDecl {
154
+ name,
155
+ mutable,
156
+ type_ann: None,
157
+ init,
158
+ span,
159
+ })
160
+ }
161
+ _ => {
162
+ let init = d
163
+ .init
164
+ .as_ref()
165
+ .map(|i| expr::convert_expr(i, ctx))
166
+ .transpose()?
167
+ .ok_or_else(|| {
168
+ ConvertError::new(ConvertErrorKind::Incompatible {
169
+ what: "destructuring declaration".into(),
170
+ reason: "initializer required".into(),
171
+ })
172
+ })?;
173
+ let pattern = expr::convert_destruct_pattern(id)?;
174
+ Ok(Statement::VarDeclDestructure {
175
+ pattern,
176
+ mutable,
177
+ init,
178
+ span,
179
+ })
180
+ }
181
+ }
182
+ } else {
183
+ Err(ConvertError::new(ConvertErrorKind::Incompatible {
184
+ what: "multi-declarator variable declaration".into(),
185
+ reason: "split into separate declarations".into(),
186
+ }))
187
+ }
188
+ }
189
+
190
+ fn convert_for_statement(
191
+ f: &oxc::ast::ast::ForStatement<'_>,
192
+ ctx: &Ctx<'_>,
193
+ span: Span,
194
+ ) -> Result<Statement, ConvertError> {
195
+ let init = f
196
+ .init
197
+ .as_ref()
198
+ .map(|i| match i {
199
+ oxc::ast::ast::ForStatementInit::VariableDeclaration(v) => {
200
+ convert_var_decl(v, ctx, span_util::stub_span()).map(Box::new)
201
+ }
202
+ _ => {
203
+ if let Some(e) = i.as_expression() {
204
+ expr::convert_expr(e, ctx).map(|expr| {
205
+ Box::new(Statement::ExprStmt {
206
+ expr,
207
+ span: span_util::stub_span(),
208
+ })
209
+ })
210
+ } else {
211
+ Err(ConvertError::new(ConvertErrorKind::Unsupported {
212
+ what: "for init".into(),
213
+ hint: None,
214
+ }))
215
+ }
216
+ }
217
+ })
218
+ .transpose()?;
219
+ let cond = f
220
+ .test
221
+ .as_ref()
222
+ .map(|e| expr::convert_expr(e, ctx))
223
+ .transpose()?;
224
+ let update = f
225
+ .update
226
+ .as_ref()
227
+ .map(|e| expr::convert_expr(e, ctx))
228
+ .transpose()?;
229
+ let body = Box::new(convert_statement(&f.body, ctx)?);
230
+ Ok(Statement::For {
231
+ init,
232
+ cond,
233
+ update,
234
+ body,
235
+ span,
236
+ })
237
+ }
238
+
239
+ fn convert_for_of_statement(
240
+ f: &oxc::ast::ast::ForOfStatement<'_>,
241
+ ctx: &Ctx<'_>,
242
+ span: Span,
243
+ ) -> Result<Statement, ConvertError> {
244
+ let name = match &f.left {
245
+ oxc::ast::ast::ForStatementLeft::VariableDeclaration(v) => {
246
+ if v.declarations.len() == 1 {
247
+ let d = &v.declarations[0];
248
+ match &d.id {
249
+ oxc::ast::ast::BindingPattern::BindingIdentifier(b) => b.name.as_str(),
250
+ _ => {
251
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
252
+ what: "for-of with destructuring".into(),
253
+ reason: "use simple identifier".into(),
254
+ }))
255
+ }
256
+ }
257
+ } else {
258
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
259
+ what: "for-of with multiple bindings".into(),
260
+ reason: "not supported".into(),
261
+ }));
262
+ }
263
+ }
264
+ _ => {
265
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
266
+ what: "for-of (use variable declaration in left)".into(),
267
+ reason: "e.g. for (const x of arr)".into(),
268
+ }))
269
+ }
270
+ };
271
+ let iterable = expr::convert_expr(&f.right, ctx)?;
272
+ let body = Box::new(convert_statement(&f.body, ctx)?);
273
+ Ok(Statement::ForOf {
274
+ name: Arc::from(name),
275
+ iterable,
276
+ body,
277
+ span,
278
+ })
279
+ }
280
+
281
+ fn convert_switch_statement(
282
+ s: &oxc::ast::ast::SwitchStatement<'_>,
283
+ ctx: &Ctx<'_>,
284
+ span: Span,
285
+ ) -> Result<Statement, ConvertError> {
286
+ let expr = expr::convert_expr(&s.discriminant, ctx)?;
287
+ let mut cases = Vec::new();
288
+ let mut default_body: Option<Vec<Statement>> = None;
289
+ for c in &s.cases {
290
+ let stmts = convert_statements(&c.consequent, ctx.0, ctx.1)?;
291
+ match &c.test {
292
+ Some(t) => cases.push((Some(expr::convert_expr(t, ctx)?), stmts)),
293
+ None => default_body = Some(stmts),
294
+ }
295
+ }
296
+ Ok(Statement::Switch {
297
+ expr,
298
+ cases,
299
+ default_body,
300
+ span,
301
+ })
302
+ }
303
+
304
+ fn convert_try_statement(
305
+ t: &oxc::ast::ast::TryStatement<'_>,
306
+ ctx: &Ctx<'_>,
307
+ span: Span,
308
+ ) -> Result<Statement, ConvertError> {
309
+ // TryStatement.block is BlockStatement; convert its body to Statement::Block
310
+ let body_stmts = convert_statements(&t.block.body, ctx.0, ctx.1)?;
311
+ let body = Box::new(Statement::Block {
312
+ statements: body_stmts,
313
+ span: span_util::oxc_span_to_tish(ctx.1, &*t.block),
314
+ });
315
+ let (catch_param, catch_body) = match &t.handler {
316
+ Some(h) => {
317
+ let param = h.param.as_ref().and_then(|cp: &oxc::ast::ast::CatchParameter<'_>| {
318
+ if let oxc::ast::ast::BindingPattern::BindingIdentifier(b) = &cp.pattern {
319
+ Some(Arc::from(b.name.as_str()))
320
+ } else {
321
+ None
322
+ }
323
+ });
324
+ let catch_stmts = convert_statements(&h.body.body, ctx.0, ctx.1)?;
325
+ let cb = Box::new(Statement::Block {
326
+ statements: catch_stmts,
327
+ span: span_util::oxc_span_to_tish(ctx.1, &*h.body),
328
+ });
329
+ (param, Some(cb))
330
+ }
331
+ None => (None, None),
332
+ };
333
+ let finally_body = t
334
+ .finalizer
335
+ .as_ref()
336
+ .map(|f| {
337
+ let stmts = convert_statements(&f.body, ctx.0, ctx.1)?;
338
+ Ok(Box::new(Statement::Block {
339
+ statements: stmts,
340
+ span: span_util::oxc_span_to_tish(ctx.1, &**f),
341
+ }))
342
+ })
343
+ .transpose()?;
344
+ Ok(Statement::Try {
345
+ body,
346
+ catch_param,
347
+ catch_body,
348
+ finally_body,
349
+ span,
350
+ })
351
+ }
352
+
353
+ fn convert_function_decl(
354
+ f: &oxc::ast::ast::Function<'_>,
355
+ ctx: &Ctx<'_>,
356
+ span: Span,
357
+ ) -> Result<Statement, ConvertError> {
358
+ let async_ = f.r#async;
359
+ let name: Arc<str> = f
360
+ .id
361
+ .as_ref()
362
+ .map(|id| Arc::from(id.name.as_str()))
363
+ .unwrap_or_else(|| Arc::from(""));
364
+ let (params, rest_param) = expr::convert_params(&f.params, ctx)?;
365
+ let body = match &f.body {
366
+ Some(fb) => {
367
+ let stmts = convert_statements(&fb.statements, ctx.0, ctx.1)?;
368
+ Box::new(Statement::Block {
369
+ statements: stmts,
370
+ span: span_util::oxc_span_to_tish(ctx.1, fb.as_ref()),
371
+ })
372
+ }
373
+ None => {
374
+ return Err(ConvertError::new(ConvertErrorKind::Incompatible {
375
+ what: "function body".into(),
376
+ reason: "expected block".into(),
377
+ }))
378
+ }
379
+ };
380
+ Ok(Statement::FunDecl {
381
+ async_,
382
+ name,
383
+ params,
384
+ rest_param,
385
+ return_type: None,
386
+ body,
387
+ span,
388
+ })
389
+ }
390
+
391
+ fn convert_import(
392
+ i: &oxc::ast::ast::ImportDeclaration<'_>,
393
+ _ctx: &Ctx<'_>,
394
+ span: Span,
395
+ ) -> Result<Statement, ConvertError> {
396
+ let from: Arc<str> = Arc::from(i.source.value.as_str());
397
+ let mut specifiers = Vec::new();
398
+ if let Some(specs) = &i.specifiers {
399
+ for s in specs.iter() {
400
+ match s {
401
+ oxc::ast::ast::ImportDeclarationSpecifier::ImportSpecifier(is) => {
402
+ let imported_name = is.imported.name().as_str();
403
+ let local_name = is.local.name.as_str();
404
+ let alias = if imported_name == local_name {
405
+ None
406
+ } else {
407
+ Some(Arc::from(local_name))
408
+ };
409
+ specifiers.push(tish_ast::ImportSpecifier::Named {
410
+ name: Arc::from(imported_name),
411
+ alias,
412
+ });
413
+ }
414
+ oxc::ast::ast::ImportDeclarationSpecifier::ImportDefaultSpecifier(ds) => {
415
+ specifiers.push(tish_ast::ImportSpecifier::Default(Arc::from(
416
+ ds.local.name.as_str(),
417
+ )));
418
+ }
419
+ oxc::ast::ast::ImportDeclarationSpecifier::ImportNamespaceSpecifier(ns) => {
420
+ specifiers.push(tish_ast::ImportSpecifier::Namespace(Arc::from(
421
+ ns.local.name.as_str(),
422
+ )));
423
+ }
424
+ }
425
+ }
426
+ }
427
+ Ok(Statement::Import {
428
+ specifiers,
429
+ from,
430
+ span,
431
+ })
432
+ }
433
+
434
+ fn convert_export_default(
435
+ e: &oxc::ast::ast::ExportDefaultDeclaration<'_>,
436
+ ctx: &Ctx<'_>,
437
+ span: Span,
438
+ ) -> Result<Statement, ConvertError> {
439
+ let declaration = if let Some(expr) = e.declaration.as_expression() {
440
+ let expr = expr::convert_expr(expr, ctx)?;
441
+ tish_ast::ExportDeclaration::Default(expr)
442
+ } else if let oxc::ast::ast::ExportDefaultDeclarationKind::FunctionDeclaration(f) = &e.declaration {
443
+ let stmt = convert_function_decl(f.as_ref(), ctx, span_util::stub_span())?;
444
+ tish_ast::ExportDeclaration::Named(Box::new(stmt))
445
+ } else {
446
+ return Err(ConvertError::new(ConvertErrorKind::Unsupported {
447
+ what: "export default (this form)".into(),
448
+ hint: None,
449
+ }));
450
+ };
451
+ Ok(Statement::Export {
452
+ declaration: Box::new(declaration),
453
+ span,
454
+ })
455
+ }
456
+
457
+ fn convert_export_named(
458
+ e: &oxc::ast::ast::ExportNamedDeclaration<'_>,
459
+ ctx: &Ctx<'_>,
460
+ span: Span,
461
+ ) -> Result<Statement, ConvertError> {
462
+ if let Some(decl) = &e.declaration {
463
+ let stmt = convert_declaration(decl, ctx)?;
464
+ Ok(Statement::Export {
465
+ declaration: Box::new(tish_ast::ExportDeclaration::Named(Box::new(stmt))),
466
+ span,
467
+ })
468
+ } else {
469
+ Err(ConvertError::new(ConvertErrorKind::Unsupported {
470
+ what: "export { ... } (re-exports)".into(),
471
+ hint: None,
472
+ }))
473
+ }
474
+ }
@@ -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 tish_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,44 @@
1
+ [package]
2
+ name = "tish"
3
+ version = "0.1.0"
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
+ # Default: secure mode with no dangerous capabilities
15
+ default = []
16
+ # Full: all capabilities enabled (for development/trusted environments)
17
+ full = ["http", "fs", "process", "regex", "ws"]
18
+ # Individual capability flags
19
+ http = ["tish_eval/http", "tish_runtime/http", "tish_compile/http", "tish_vm/http"]
20
+ fs = ["tish_eval/fs", "tish_runtime/fs", "tish_compile/fs", "tish_vm/fs"]
21
+ process = ["tish_eval/process", "tish_runtime/process", "tish_compile/process", "tish_vm/process"]
22
+ regex = ["tish_eval/regex", "tish_runtime/regex", "tish_compile/regex", "tish_vm/regex"]
23
+ ws = ["tish_eval/ws", "tish_runtime/ws", "tish_compile/ws", "tish_vm/ws"]
24
+ [dependencies]
25
+ rustyline = { version = "17", features = ["with-file-history"] }
26
+ tish_lexer = { path = "../tish_lexer" }
27
+ tish_ast = { path = "../tish_ast" }
28
+ tish_parser = { path = "../tish_parser" }
29
+ tish_eval = { path = "../tish_eval" }
30
+ tish_compile = { path = "../tish_compile" }
31
+ tish_compile_js = { path = "../tish_compile_js" }
32
+ tish_bytecode = { path = "../tish_bytecode" }
33
+ tish_opt = { path = "../tish_opt" }
34
+ tish_vm = { path = "../tish_vm" }
35
+ tish_native = { path = "../tish_native" }
36
+ tish_llvm = { path = "../tish_llvm" }
37
+ tish_wasm = { path = "../tish_wasm" }
38
+ tish_runtime = { path = "../tish_runtime" }
39
+ tish_core = { path = "../tish_core" }
40
+ js_to_tish = { path = "../js_to_tish" }
41
+ clap = { version = "4.6.0", features = ["derive"] }
42
+
43
+ [dev-dependencies]
44
+ rayon = "1.11"