@tishlang/tish 1.5.0 → 1.7.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 (85) hide show
  1. package/Cargo.toml +1 -0
  2. package/bin/tish +0 -0
  3. package/crates/js_to_tish/src/error.rs +2 -8
  4. package/crates/js_to_tish/src/transform/expr.rs +101 -130
  5. package/crates/js_to_tish/src/transform/stmt.rs +25 -22
  6. package/crates/tish/Cargo.toml +1 -1
  7. package/crates/tish/src/cli_help.rs +76 -29
  8. package/crates/tish/src/main.rs +85 -54
  9. package/crates/tish/tests/cargo_example_compile.rs +67 -0
  10. package/crates/tish/tests/fixtures/cargo_example_project/Cargo.toml +3 -0
  11. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/Cargo.toml +11 -0
  12. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/src/lib.rs +12 -0
  13. package/crates/tish/tests/fixtures/cargo_example_project/package.json +10 -0
  14. package/crates/tish/tests/fixtures/cargo_example_project/src/main.tish +3 -0
  15. package/crates/tish/tests/integration_test.rs +197 -47
  16. package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
  17. package/crates/tish/tests/shortcircuit.rs +19 -4
  18. package/crates/tish_ast/src/ast.rs +12 -14
  19. package/crates/tish_build_utils/src/lib.rs +64 -6
  20. package/crates/tish_builtins/src/array.rs +52 -21
  21. package/crates/tish_builtins/src/construct.rs +2 -8
  22. package/crates/tish_builtins/src/globals.rs +30 -15
  23. package/crates/tish_builtins/src/lib.rs +5 -5
  24. package/crates/tish_builtins/src/math.rs +5 -3
  25. package/crates/tish_builtins/src/string.rs +71 -19
  26. package/crates/tish_bytecode/src/chunk.rs +0 -1
  27. package/crates/tish_bytecode/src/compiler.rs +164 -60
  28. package/crates/tish_bytecode/src/opcode.rs +13 -4
  29. package/crates/tish_bytecode/src/peephole.rs +2 -2
  30. package/crates/tish_compile/Cargo.toml +1 -0
  31. package/crates/tish_compile/src/codegen.rs +989 -318
  32. package/crates/tish_compile/src/infer.rs +69 -19
  33. package/crates/tish_compile/src/lib.rs +21 -8
  34. package/crates/tish_compile/src/resolve.rs +515 -94
  35. package/crates/tish_compile/src/types.rs +10 -14
  36. package/crates/tish_compile_js/src/codegen.rs +34 -13
  37. package/crates/tish_compile_js/src/tests_jsx.rs +30 -6
  38. package/crates/tish_compiler_wasm/src/lib.rs +16 -13
  39. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +40 -48
  40. package/crates/tish_core/src/json.rs +5 -3
  41. package/crates/tish_core/src/lib.rs +1 -1
  42. package/crates/tish_core/src/uri.rs +9 -6
  43. package/crates/tish_core/src/value.rs +92 -28
  44. package/crates/tish_cranelift/src/link.rs +6 -9
  45. package/crates/tish_cranelift/src/lower.rs +14 -8
  46. package/crates/tish_eval/src/eval.rs +398 -141
  47. package/crates/tish_eval/src/lib.rs +10 -6
  48. package/crates/tish_eval/src/natives.rs +95 -38
  49. package/crates/tish_eval/src/promise.rs +14 -8
  50. package/crates/tish_eval/src/timers.rs +28 -19
  51. package/crates/tish_eval/src/value.rs +10 -3
  52. package/crates/tish_fmt/src/lib.rs +29 -13
  53. package/crates/tish_lexer/src/lib.rs +217 -63
  54. package/crates/tish_lexer/src/token.rs +6 -6
  55. package/crates/tish_llvm/src/lib.rs +15 -8
  56. package/crates/tish_lsp/src/main.rs +41 -43
  57. package/crates/tish_native/src/build.rs +38 -15
  58. package/crates/tish_native/src/lib.rs +76 -32
  59. package/crates/tish_opt/src/lib.rs +67 -50
  60. package/crates/tish_parser/src/lib.rs +36 -11
  61. package/crates/tish_parser/src/parser.rs +172 -87
  62. package/crates/tish_runtime/src/http.rs +15 -6
  63. package/crates/tish_runtime/src/http_fetch.rs +24 -14
  64. package/crates/tish_runtime/src/lib.rs +224 -168
  65. package/crates/tish_runtime/src/promise.rs +1 -5
  66. package/crates/tish_runtime/src/ws.rs +45 -20
  67. package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
  68. package/crates/tish_ui/src/jsx.rs +41 -22
  69. package/crates/tish_ui/src/lib.rs +2 -2
  70. package/crates/tish_vm/src/vm.rs +320 -116
  71. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +8 -3
  72. package/crates/tish_wasm/src/lib.rs +38 -28
  73. package/crates/tishlang_cargo_bindgen/Cargo.toml +25 -0
  74. package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
  75. package/crates/tishlang_cargo_bindgen/src/discover.rs +52 -0
  76. package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
  77. package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
  78. package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
  79. package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -0
  80. package/package.json +1 -1
  81. package/platform/darwin-arm64/tish +0 -0
  82. package/platform/darwin-x64/tish +0 -0
  83. package/platform/linux-arm64/tish +0 -0
  84. package/platform/linux-x64/tish +0 -0
  85. package/platform/win32-x64/tish.exe +0 -0
package/Cargo.toml CHANGED
@@ -28,6 +28,7 @@ members = [
28
28
  "crates/tish_fmt",
29
29
  "crates/tish_lint",
30
30
  "crates/tish_lsp",
31
+ "crates/tishlang_cargo_bindgen",
31
32
  ]
32
33
  resolver = "2"
33
34
 
package/bin/tish CHANGED
Binary file
@@ -30,15 +30,9 @@ pub enum ConvertErrorKind {
30
30
  /// Semantic analysis error from OXC.
31
31
  Semantic(String),
32
32
  /// Unsupported construct (class, this, for-in, etc.).
33
- Unsupported {
34
- what: String,
35
- hint: Option<String>,
36
- },
33
+ Unsupported { what: String, hint: Option<String> },
37
34
  /// JS feature that cannot be expressed in Tish.
38
- Incompatible {
39
- what: String,
40
- reason: String,
41
- },
35
+ Incompatible { what: String, reason: String },
42
36
  }
43
37
 
44
38
  impl fmt::Display for ConvertErrorKind {
@@ -5,8 +5,8 @@ use std::sync::Arc;
5
5
  use oxc::ast::ast::Expression as OxcExpr;
6
6
  use oxc::semantic::Semantic;
7
7
  use tishlang_ast::{
8
- ArrayElement, ArrowBody, BinOp, CompoundOp, DestructPattern, Expr, Literal, LogicalAssignOp,
9
- FunParam, MemberProp, ObjectProp, TypedParam,
8
+ ArrayElement, ArrowBody, BinOp, CompoundOp, DestructPattern, Expr, FunParam, Literal,
9
+ LogicalAssignOp, MemberProp, ObjectProp, TypedParam,
10
10
  };
11
11
 
12
12
  use crate::error::{ConvertError, ConvertErrorKind};
@@ -57,7 +57,12 @@ pub fn convert_expr(expr: &OxcExpr<'_>, ctx: &Ctx<'_>) -> Result<Expr, ConvertEr
57
57
  let left = Box::new(convert_expr(&b.left, ctx)?);
58
58
  let right = Box::new(convert_expr(&b.right, ctx)?);
59
59
  let op = convert_bin_op(&b.operator)?;
60
- Ok(Expr::Binary { left, op, right, span })
60
+ Ok(Expr::Binary {
61
+ left,
62
+ op,
63
+ right,
64
+ span,
65
+ })
61
66
  }
62
67
  OxcExpr::UnaryExpression(u) => {
63
68
  let operand = Box::new(convert_expr(&u.argument, ctx)?);
@@ -112,10 +117,7 @@ pub fn convert_expr(expr: &OxcExpr<'_>, ctx: &Ctx<'_>) -> Result<Expr, ConvertEr
112
117
  })
113
118
  }
114
119
  OxcExpr::LogicalExpression(l) => {
115
- if matches!(
116
- l.operator,
117
- oxc::ast::ast::LogicalOperator::Coalesce
118
- ) {
120
+ if matches!(l.operator, oxc::ast::ast::LogicalOperator::Coalesce) {
119
121
  Ok(Expr::NullishCoalesce {
120
122
  left: Box::new(convert_expr(&l.left, ctx)?),
121
123
  right: Box::new(convert_expr(&l.right, ctx)?),
@@ -155,12 +157,12 @@ pub fn convert_expr(expr: &OxcExpr<'_>, ctx: &Ctx<'_>) -> Result<Expr, ConvertEr
155
157
  OxcExpr::ArrowFunctionExpression(arrow) => {
156
158
  let params = convert_arrow_params(&arrow.params, ctx)?;
157
159
  let body = if arrow.expression {
158
- let e = arrow
159
- .get_expression()
160
- .ok_or_else(|| ConvertError::new(ConvertErrorKind::Incompatible {
160
+ let e = arrow.get_expression().ok_or_else(|| {
161
+ ConvertError::new(ConvertErrorKind::Incompatible {
161
162
  what: "arrow expression body".into(),
162
163
  reason: "expected expression".into(),
163
- }))?;
164
+ })
165
+ })?;
164
166
  ArrowBody::Expr(Box::new(convert_expr(e, ctx)?))
165
167
  } else {
166
168
  let stmts = super::stmt::convert_statements(&arrow.body.statements, ctx.0, ctx.1)?;
@@ -169,11 +171,7 @@ pub fn convert_expr(expr: &OxcExpr<'_>, ctx: &Ctx<'_>) -> Result<Expr, ConvertEr
169
171
  span: span_util::oxc_span_to_tish(ctx.1, &*arrow.body),
170
172
  }))
171
173
  };
172
- Ok(Expr::ArrowFunction {
173
- params,
174
- body,
175
- span,
176
- })
174
+ Ok(Expr::ArrowFunction { params, body, span })
177
175
  }
178
176
  OxcExpr::AwaitExpression(a) => Ok(Expr::Await {
179
177
  operand: Box::new(convert_expr(&a.argument, ctx)?),
@@ -226,11 +224,7 @@ pub fn convert_expr(expr: &OxcExpr<'_>, ctx: &Ctx<'_>) -> Result<Expr, ConvertEr
226
224
  }))
227
225
  }
228
226
  };
229
- Ok(Expr::ArrowFunction {
230
- params,
231
- body,
232
- span,
233
- })
227
+ Ok(Expr::ArrowFunction { params, body, span })
234
228
  }
235
229
  _ => Err(ConvertError::new(ConvertErrorKind::Unsupported {
236
230
  what: format!("expression: {:?}", std::mem::discriminant(expr)),
@@ -285,7 +279,10 @@ fn convert_call_arg(
285
279
  ) -> Result<tishlang_ast::CallArg, ConvertError> {
286
280
  if arg.is_spread() {
287
281
  if let oxc::ast::ast::Argument::SpreadElement(s) = arg {
288
- Ok(tishlang_ast::CallArg::Spread(convert_expr(&s.argument, ctx)?))
282
+ Ok(tishlang_ast::CallArg::Spread(convert_expr(
283
+ &s.argument,
284
+ ctx,
285
+ )?))
289
286
  } else {
290
287
  unreachable!()
291
288
  }
@@ -307,10 +304,12 @@ fn convert_array_element(
307
304
  oxc::ast::ast::ArrayExpressionElement::SpreadElement(s) => {
308
305
  Ok(ArrayElement::Spread(convert_expr(&s.argument, ctx)?))
309
306
  }
310
- oxc::ast::ast::ArrayExpressionElement::Elision(_) => Ok(ArrayElement::Expr(Expr::Literal {
311
- value: Literal::Null,
312
- span: span_util::stub_span(),
313
- })),
307
+ oxc::ast::ast::ArrayExpressionElement::Elision(_) => {
308
+ Ok(ArrayElement::Expr(Expr::Literal {
309
+ value: Literal::Null,
310
+ span: span_util::stub_span(),
311
+ }))
312
+ }
314
313
  _ => {
315
314
  if let Some(e) = el.as_expression() {
316
315
  Ok(ArrayElement::Expr(convert_expr(e, ctx)?))
@@ -358,77 +357,59 @@ fn convert_assignment(
358
357
  let name = id.name.as_str();
359
358
  let value = Box::new(convert_expr(right, ctx)?);
360
359
  return match &a.operator {
361
- oxc::ast::ast::AssignmentOperator::Assign => {
362
- Ok(Expr::Assign {
363
- name: Arc::from(name),
364
- value,
365
- span,
366
- })
367
- }
368
- oxc::ast::ast::AssignmentOperator::Addition => {
369
- Ok(Expr::CompoundAssign {
370
- name: Arc::from(name),
371
- op: CompoundOp::Add,
372
- value,
373
- span,
374
- })
375
- }
376
- oxc::ast::ast::AssignmentOperator::Subtraction => {
377
- Ok(Expr::CompoundAssign {
378
- name: Arc::from(name),
379
- op: CompoundOp::Sub,
380
- value,
381
- span,
382
- })
383
- }
384
- oxc::ast::ast::AssignmentOperator::Multiplication => {
385
- Ok(Expr::CompoundAssign {
386
- name: Arc::from(name),
387
- op: CompoundOp::Mul,
388
- value,
389
- span,
390
- })
391
- }
392
- oxc::ast::ast::AssignmentOperator::Division => {
393
- Ok(Expr::CompoundAssign {
394
- name: Arc::from(name),
395
- op: CompoundOp::Div,
396
- value,
397
- span,
398
- })
399
- }
400
- oxc::ast::ast::AssignmentOperator::Remainder => {
401
- Ok(Expr::CompoundAssign {
402
- name: Arc::from(name),
403
- op: CompoundOp::Mod,
404
- value,
405
- span,
406
- })
407
- }
408
- oxc::ast::ast::AssignmentOperator::LogicalAnd => {
409
- Ok(Expr::LogicalAssign {
410
- name: Arc::from(name),
411
- op: LogicalAssignOp::AndAnd,
412
- value,
413
- span,
414
- })
415
- }
416
- oxc::ast::ast::AssignmentOperator::LogicalOr => {
417
- Ok(Expr::LogicalAssign {
418
- name: Arc::from(name),
419
- op: LogicalAssignOp::OrOr,
420
- value,
421
- span,
422
- })
423
- }
424
- oxc::ast::ast::AssignmentOperator::LogicalNullish => {
425
- Ok(Expr::LogicalAssign {
426
- name: Arc::from(name),
427
- op: LogicalAssignOp::Nullish,
428
- value,
429
- span,
430
- })
431
- }
360
+ oxc::ast::ast::AssignmentOperator::Assign => Ok(Expr::Assign {
361
+ name: Arc::from(name),
362
+ value,
363
+ span,
364
+ }),
365
+ oxc::ast::ast::AssignmentOperator::Addition => Ok(Expr::CompoundAssign {
366
+ name: Arc::from(name),
367
+ op: CompoundOp::Add,
368
+ value,
369
+ span,
370
+ }),
371
+ oxc::ast::ast::AssignmentOperator::Subtraction => Ok(Expr::CompoundAssign {
372
+ name: Arc::from(name),
373
+ op: CompoundOp::Sub,
374
+ value,
375
+ span,
376
+ }),
377
+ oxc::ast::ast::AssignmentOperator::Multiplication => Ok(Expr::CompoundAssign {
378
+ name: Arc::from(name),
379
+ op: CompoundOp::Mul,
380
+ value,
381
+ span,
382
+ }),
383
+ oxc::ast::ast::AssignmentOperator::Division => Ok(Expr::CompoundAssign {
384
+ name: Arc::from(name),
385
+ op: CompoundOp::Div,
386
+ value,
387
+ span,
388
+ }),
389
+ oxc::ast::ast::AssignmentOperator::Remainder => Ok(Expr::CompoundAssign {
390
+ name: Arc::from(name),
391
+ op: CompoundOp::Mod,
392
+ value,
393
+ span,
394
+ }),
395
+ oxc::ast::ast::AssignmentOperator::LogicalAnd => Ok(Expr::LogicalAssign {
396
+ name: Arc::from(name),
397
+ op: LogicalAssignOp::AndAnd,
398
+ value,
399
+ span,
400
+ }),
401
+ oxc::ast::ast::AssignmentOperator::LogicalOr => Ok(Expr::LogicalAssign {
402
+ name: Arc::from(name),
403
+ op: LogicalAssignOp::OrOr,
404
+ value,
405
+ span,
406
+ }),
407
+ oxc::ast::ast::AssignmentOperator::LogicalNullish => Ok(Expr::LogicalAssign {
408
+ name: Arc::from(name),
409
+ op: LogicalAssignOp::Nullish,
410
+ value,
411
+ span,
412
+ }),
432
413
  _ => Err(ConvertError::new(ConvertErrorKind::Unsupported {
433
414
  what: "assignment operator".into(),
434
415
  hint: None,
@@ -458,24 +439,14 @@ fn convert_update_expr(
458
439
  }
459
440
  };
460
441
  Ok(match (u.operator, u.prefix) {
461
- (oxc::ast::ast::UpdateOperator::Increment, true) => {
462
- Expr::PrefixInc { name, span }
463
- }
464
- (oxc::ast::ast::UpdateOperator::Increment, false) => {
465
- Expr::PostfixInc { name, span }
466
- }
467
- (oxc::ast::ast::UpdateOperator::Decrement, true) => {
468
- Expr::PrefixDec { name, span }
469
- }
470
- (oxc::ast::ast::UpdateOperator::Decrement, false) => {
471
- Expr::PostfixDec { name, span }
472
- }
442
+ (oxc::ast::ast::UpdateOperator::Increment, true) => Expr::PrefixInc { name, span },
443
+ (oxc::ast::ast::UpdateOperator::Increment, false) => Expr::PostfixInc { name, span },
444
+ (oxc::ast::ast::UpdateOperator::Decrement, true) => Expr::PrefixDec { name, span },
445
+ (oxc::ast::ast::UpdateOperator::Decrement, false) => Expr::PostfixDec { name, span },
473
446
  })
474
447
  }
475
448
 
476
- fn convert_bin_op(
477
- op: &oxc::ast::ast::BinaryOperator,
478
- ) -> Result<BinOp, ConvertError> {
449
+ fn convert_bin_op(op: &oxc::ast::ast::BinaryOperator) -> Result<BinOp, ConvertError> {
479
450
  Ok(match op {
480
451
  oxc::ast::ast::BinaryOperator::Equality => BinOp::Eq,
481
452
  oxc::ast::ast::BinaryOperator::Inequality => BinOp::Ne,
@@ -554,24 +525,24 @@ pub fn convert_params(
554
525
  let fp = p;
555
526
  {
556
527
  let name = match &fp.pattern {
557
- oxc::ast::ast::BindingPattern::BindingIdentifier(b) => b.name.as_str(),
558
- _ => {
559
- return Err(ConvertError::new(ConvertErrorKind::Unsupported {
560
- what: "destructuring in params".into(),
561
- hint: None,
562
- }))
563
- }
564
- };
565
- let default = fp
566
- .initializer
567
- .as_ref()
568
- .map(|e| convert_expr(e, ctx))
569
- .transpose()?;
570
- typed_params.push(FunParam::Simple(TypedParam {
571
- name: Arc::from(name),
572
- type_ann: None,
573
- default,
574
- }));
528
+ oxc::ast::ast::BindingPattern::BindingIdentifier(b) => b.name.as_str(),
529
+ _ => {
530
+ return Err(ConvertError::new(ConvertErrorKind::Unsupported {
531
+ what: "destructuring in params".into(),
532
+ hint: None,
533
+ }))
534
+ }
535
+ };
536
+ let default = fp
537
+ .initializer
538
+ .as_ref()
539
+ .map(|e| convert_expr(e, ctx))
540
+ .transpose()?;
541
+ typed_params.push(FunParam::Simple(TypedParam {
542
+ name: Arc::from(name),
543
+ type_ann: None,
544
+ default,
545
+ }));
575
546
  }
576
547
  }
577
548
  if rest_param.is_none() {
@@ -4,7 +4,7 @@ use std::sync::Arc;
4
4
 
5
5
  use oxc::ast::ast::Statement as OxcStmt;
6
6
  use oxc::semantic::Semantic;
7
- use tishlang_ast::{Statement, Span};
7
+ use tishlang_ast::{Span, Statement};
8
8
 
9
9
  use super::expr;
10
10
  use crate::error::{ConvertError, ConvertErrorKind};
@@ -19,9 +19,7 @@ pub fn convert_statements(
19
19
  source: &str,
20
20
  ) -> Result<Vec<Statement>, ConvertError> {
21
21
  let ctx = (semantic, source);
22
- body.iter()
23
- .map(|s| convert_statement(s, &ctx))
24
- .collect()
22
+ body.iter().map(|s| convert_statement(s, &ctx)).collect()
25
23
  }
26
24
 
27
25
  fn convert_statement(stmt: &OxcStmt<'_>, ctx: &Ctx<'_>) -> Result<Statement, ConvertError> {
@@ -29,10 +27,7 @@ fn convert_statement(stmt: &OxcStmt<'_>, ctx: &Ctx<'_>) -> Result<Statement, Con
29
27
  match stmt {
30
28
  OxcStmt::BlockStatement(b) => {
31
29
  let statements = convert_statements(&b.body, ctx.0, ctx.1)?;
32
- Ok(Statement::Block {
33
- statements,
34
- span,
35
- })
30
+ Ok(Statement::Block { statements, span })
36
31
  }
37
32
  OxcStmt::VariableDeclaration(v) => convert_var_decl(v, ctx, span),
38
33
  OxcStmt::ExpressionStatement(e) => {
@@ -146,7 +141,11 @@ fn convert_var_decl(
146
141
  if v.declarations.len() == 1 {
147
142
  let d = &v.declarations[0];
148
143
  let id = &d.id;
149
- let init = d.init.as_ref().map(|i| expr::convert_expr(i, ctx)).transpose()?;
144
+ let init = d
145
+ .init
146
+ .as_ref()
147
+ .map(|i| expr::convert_expr(i, ctx))
148
+ .transpose()?;
150
149
  match id {
151
150
  oxc::ast::ast::BindingPattern::BindingIdentifier(b) => {
152
151
  let name: Arc<str> = Arc::from(b.name.as_str());
@@ -314,13 +313,16 @@ fn convert_try_statement(
314
313
  });
315
314
  let (catch_param, catch_body) = match &t.handler {
316
315
  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
- });
316
+ let param = h
317
+ .param
318
+ .as_ref()
319
+ .and_then(|cp: &oxc::ast::ast::CatchParameter<'_>| {
320
+ if let oxc::ast::ast::BindingPattern::BindingIdentifier(b) = &cp.pattern {
321
+ Some(Arc::from(b.name.as_str()))
322
+ } else {
323
+ None
324
+ }
325
+ });
324
326
  let catch_stmts = convert_statements(&h.body.body, ctx.0, ctx.1)?;
325
327
  let cb = Box::new(Statement::Block {
326
328
  statements: catch_stmts,
@@ -356,11 +358,10 @@ fn convert_function_decl(
356
358
  span: Span,
357
359
  ) -> Result<Statement, ConvertError> {
358
360
  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(""));
361
+ let name: Arc<str> =
362
+ f.id.as_ref()
363
+ .map(|id| Arc::from(id.name.as_str()))
364
+ .unwrap_or_else(|| Arc::from(""));
364
365
  let (params, rest_param) = expr::convert_params(&f.params, ctx)?;
365
366
  let body = match &f.body {
366
367
  Some(fb) => {
@@ -439,7 +440,9 @@ fn convert_export_default(
439
440
  let declaration = if let Some(expr) = e.declaration.as_expression() {
440
441
  let expr = expr::convert_expr(expr, ctx)?;
441
442
  tishlang_ast::ExportDeclaration::Default(expr)
442
- } else if let oxc::ast::ast::ExportDefaultDeclarationKind::FunctionDeclaration(f) = &e.declaration {
443
+ } else if let oxc::ast::ast::ExportDefaultDeclarationKind::FunctionDeclaration(f) =
444
+ &e.declaration
445
+ {
443
446
  let stmt = convert_function_decl(f.as_ref(), ctx, span_util::stub_span())?;
444
447
  tishlang_ast::ExportDeclaration::Named(Box::new(stmt))
445
448
  } else {
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tishlang"
3
- version = "1.5.0"
3
+ version = "1.7.0"
4
4
  edition = "2021"
5
5
  description = "Tish CLI - run, REPL, compile to native"
6
6
  license-file = { workspace = true }
@@ -9,7 +9,7 @@ use clap::{CommandFactory, Parser, Subcommand};
9
9
 
10
10
  /// FIGlet-style block letters (UTF-8). On a TTY, a short expand + palette-color animation runs.
11
11
  const TISH_BANNER_LINES: &[&str] = &[
12
- "",
12
+ "",
13
13
  "████████╗██╗███████╗██╗ ██╗",
14
14
  "╚══██╔══╝██║██╔════╝██║ ██║",
15
15
  " ██║ ██║███████╗███████║",
@@ -26,13 +26,13 @@ const BANNER_FRAME_MS: u64 = 20;
26
26
 
27
27
  /// Orange → Yellow → Green → Teal → Blue → Purple → Pink (matching the brand palette).
28
28
  const PALETTE: &[(u8, u8, u8)] = &[
29
- (255, 159, 64), // Orange
30
- (255, 213, 64), // Yellow
31
- ( 52, 199, 89), // Green
32
- ( 48, 209, 188), // Teal
33
- ( 10, 132, 255), // Blue
34
- (175, 82, 222), // Purple
35
- (255, 55, 148), // Pink
29
+ (255, 159, 64), // Orange
30
+ (255, 213, 64), // Yellow
31
+ (52, 199, 89), // Green
32
+ (48, 209, 188), // Teal
33
+ (10, 132, 255), // Blue
34
+ (175, 82, 222), // Purple
35
+ (255, 55, 148), // Pink
36
36
  ];
37
37
 
38
38
  fn ease_out_cubic(t: f32) -> f32 {
@@ -128,8 +128,8 @@ pub fn print_tish_banner() {
128
128
  pub fn build_command() -> clap::Command {
129
129
  Cli::command()
130
130
  .after_help(cli_after_help())
131
- .mut_subcommand("run", |sub| sub.after_help(run_after_help()))
132
- .mut_subcommand("repl", |sub| sub.after_help(repl_after_help()))
131
+ .mut_subcommand("run", |sub| sub.after_help(run_after_help()))
132
+ .mut_subcommand("repl", |sub| sub.after_help(repl_after_help()))
133
133
  .mut_subcommand("build", |sub| sub.after_long_help(build_after_help()))
134
134
  }
135
135
 
@@ -138,7 +138,10 @@ fn count_help_lines(cmd: &mut clap::Command, sub_name: Option<&str>) -> usize {
138
138
  let mut buf = Vec::<u8>::new();
139
139
  if let Some(name) = sub_name {
140
140
  if cmd.find_subcommand(name).is_some() {
141
- let _ = cmd.find_subcommand_mut(name).unwrap().write_long_help(&mut buf);
141
+ let _ = cmd
142
+ .find_subcommand_mut(name)
143
+ .unwrap()
144
+ .write_long_help(&mut buf);
142
145
  } else {
143
146
  let _ = cmd.write_long_help(&mut buf);
144
147
  }
@@ -236,8 +239,11 @@ pub fn print_banner_with_help(argv: &[String]) {
236
239
  let mut out = io::stdout().lock();
237
240
  write_tish_banner_frame(&mut out, 1.0, 0);
238
241
  let _ = writeln!(out); // blank separator (row n+1)
239
- // ── Manual prefix (MAIN_PREFIX_LINES = 4 lines) ──────────────────
240
- let _ = writeln!(out, "{H_PURPLE}Tish{H_RESET} {H_GREY}(version {VERSION}){H_RESET}");
242
+ // ── Manual prefix (MAIN_PREFIX_LINES = 4 lines) ──────────────────
243
+ let _ = writeln!(
244
+ out,
245
+ "{H_PURPLE}Tish{H_RESET} {H_GREY}(version {VERSION}){H_RESET}"
246
+ );
241
247
  let _ = writeln!(out, "Minimal TS/JS-ish language");
242
248
  let _ = writeln!(out, "{H_PINK}https://tishlang.com{H_RESET}");
243
249
  let _ = writeln!(out); // blank before Usage
@@ -289,20 +295,24 @@ fn rgb_bold(r: u8, g: u8, b: u8) -> Style {
289
295
  /// Orange → section headers / usage. Teal → literals (commands, flags). Yellow → placeholders.
290
296
  pub fn cargo_help_styles() -> Styles {
291
297
  Styles::styled()
292
- .header(rgb_bold(255, 159, 64)) // Orange – "Commands:", "Options:", "Usage:"
293
- .usage(rgb_bold(255, 159, 64)) // Orange
294
- .literal(rgb_bold( 48, 209, 188)) // Teal – run, repl, --help, -V …
295
- .placeholder(rgb_bold(255, 213, 64)) // Yellow – <FILE>, <NAME>, …
296
- .error(rgb_bold(255, 55, 148)) // Pink – error messages
297
- .valid(rgb_bold( 52, 199, 89)) // Green – valid values
298
- .invalid(rgb_bold(255, 55, 148)) // Pink – invalid values
298
+ .header(rgb_bold(255, 159, 64)) // Orange – "Commands:", "Options:", "Usage:"
299
+ .usage(rgb_bold(255, 159, 64)) // Orange
300
+ .literal(rgb_bold(48, 209, 188)) // Teal – run, repl, --help, -V …
301
+ .placeholder(rgb_bold(255, 213, 64)) // Yellow – <FILE>, <NAME>, …
302
+ .error(rgb_bold(255, 55, 148)) // Pink – error messages
303
+ .valid(rgb_bold(52, 199, 89)) // Green – valid values
304
+ .invalid(rgb_bold(255, 55, 148)) // Pink – invalid values
299
305
  }
300
306
 
301
307
  /// Returns the colored `after_help` text for the top-level `tish --help`.
302
308
  /// Colors are emitted only when stdout is a TTY.
303
309
  pub fn cli_after_help() -> String {
304
310
  let (oh, t, r) = if io::stdout().is_terminal() {
305
- ("\x1b[1;38;2;255;159;64m", "\x1b[1;38;2;48;209;188m", "\x1b[0m")
311
+ (
312
+ "\x1b[1;38;2;255;159;64m",
313
+ "\x1b[1;38;2;48;209;188m",
314
+ "\x1b[0m",
315
+ )
306
316
  } else {
307
317
  ("", "", "")
308
318
  };
@@ -346,7 +356,11 @@ Omit --feature to use every capability linked into this binary."
346
356
  /// Returns the colored `after_help` for `tish run --help`.
347
357
  pub fn run_after_help() -> String {
348
358
  let (oh, t, r) = if io::stdout().is_terminal() {
349
- ("\x1b[1;38;2;255;159;64m", "\x1b[1;38;2;48;209;188m", "\x1b[0m")
359
+ (
360
+ "\x1b[1;38;2;255;159;64m",
361
+ "\x1b[1;38;2;48;209;188m",
362
+ "\x1b[0m",
363
+ )
350
364
  } else {
351
365
  ("", "", "")
352
366
  };
@@ -356,7 +370,11 @@ pub fn run_after_help() -> String {
356
370
  /// Returns the colored `after_help` for `tish repl --help`.
357
371
  pub fn repl_after_help() -> String {
358
372
  let (oh, t, r) = if io::stdout().is_terminal() {
359
- ("\x1b[1;38;2;255;159;64m", "\x1b[1;38;2;48;209;188m", "\x1b[0m")
373
+ (
374
+ "\x1b[1;38;2;255;159;64m",
375
+ "\x1b[1;38;2;48;209;188m",
376
+ "\x1b[0m",
377
+ )
360
378
  } else {
361
379
  ("", "", "")
362
380
  };
@@ -366,7 +384,11 @@ pub fn repl_after_help() -> String {
366
384
  /// Returns the colored `after_long_help` for `tish build --help`.
367
385
  pub fn build_after_help() -> String {
368
386
  let (oh, t, r) = if io::stdout().is_terminal() {
369
- ("\x1b[1;38;2;255;159;64m", "\x1b[1;38;2;48;209;188m", "\x1b[0m")
387
+ (
388
+ "\x1b[1;38;2;255;159;64m",
389
+ "\x1b[1;38;2;48;209;188m",
390
+ "\x1b[0m",
391
+ )
370
392
  } else {
371
393
  ("", "", "")
372
394
  };
@@ -421,10 +443,20 @@ pub(crate) struct Cli {
421
443
  #[derive(Parser)]
422
444
  pub(crate) struct RunArgs {
423
445
  /// Path to a `.tish` file, or `-` to read the program from stdin (like `node -`).
424
- #[arg(required = true, allow_hyphen_values = true, value_name = "FILE", help_heading = "Arguments")]
446
+ #[arg(
447
+ required = true,
448
+ allow_hyphen_values = true,
449
+ value_name = "FILE",
450
+ help_heading = "Arguments"
451
+ )]
425
452
  pub file: String,
426
453
  /// `vm` or `interp` (see `tish --help` for capabilities / `--feature`).
427
- #[arg(long, default_value = "vm", value_name = "NAME", help_heading = "Options")]
454
+ #[arg(
455
+ long,
456
+ default_value = "vm",
457
+ value_name = "NAME",
458
+ help_heading = "Options"
459
+ )]
428
460
  pub backend: String,
429
461
  /// Subset of capabilities (see `tish --help` for the full list).
430
462
  #[arg(
@@ -442,7 +474,12 @@ pub(crate) struct RunArgs {
442
474
  #[derive(Parser)]
443
475
  pub(crate) struct ReplArgs {
444
476
  /// `vm` or `interp` (see `tish --help`).
445
- #[arg(long, default_value = "vm", value_name = "NAME", help_heading = "Options")]
477
+ #[arg(
478
+ long,
479
+ default_value = "vm",
480
+ value_name = "NAME",
481
+ help_heading = "Options"
482
+ )]
446
483
  pub backend: String,
447
484
  /// Subset of capabilities (see `tish --help` for the full list).
448
485
  #[arg(
@@ -467,10 +504,20 @@ pub(crate) struct BuildArgs {
467
504
  )]
468
505
  pub output: String,
469
506
  /// `native`, `js`, `wasm`, or `wasi` (see long help below).
470
- #[arg(long, default_value = "native", value_name = "TARGET", help_heading = "Options")]
507
+ #[arg(
508
+ long,
509
+ default_value = "native",
510
+ value_name = "TARGET",
511
+ help_heading = "Options"
512
+ )]
471
513
  pub target: String,
472
514
  /// `rust`, `cranelift`, or `llvm` (only for `--target native`).
473
- #[arg(long, default_value = "rust", value_name = "BACKEND", help_heading = "Options")]
515
+ #[arg(
516
+ long,
517
+ default_value = "rust",
518
+ value_name = "BACKEND",
519
+ help_heading = "Options"
520
+ )]
474
521
  pub native_backend: String,
475
522
  /// Capability subset for native output (see long help below).
476
523
  #[arg(