@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
@@ -28,11 +28,24 @@ fn runtime_features_for_cargo(features: &[String]) -> Vec<String> {
28
28
  out
29
29
  }
30
30
 
31
+ /// Inject `mod generated_native;` after the crate attribute so the binary crate can call `crate::generated_native::…`.
32
+ fn inject_generated_native_mod(rust_code: &str) -> String {
33
+ if let Some(pos) = rust_code.find("\n\n") {
34
+ let (a, b) = rust_code.split_at(pos + 2);
35
+ format!("{}mod generated_native;\n{}", a, b)
36
+ } else {
37
+ format!("{}\n\nmod generated_native;\n", rust_code)
38
+ }
39
+ }
40
+
31
41
  pub fn build_via_cargo(
32
42
  rust_code: &str,
33
43
  native_modules: Vec<ResolvedNativeModule>,
34
44
  output_path: &Path,
35
45
  features: &[String],
46
+ extra_dependencies_toml: &str,
47
+ generated_native_rs: Option<&str>,
48
+ project_root: Option<&Path>,
36
49
  ) -> Result<(), String> {
37
50
  let out_name = output_path
38
51
  .file_stem()
@@ -40,7 +53,7 @@ pub fn build_via_cargo(
40
53
  .unwrap_or("tish_out");
41
54
  let build_dir = tishlang_build_utils::create_build_dir("tish_build", out_name)?;
42
55
 
43
- let runtime_path = tishlang_build_utils::find_runtime_path()?;
56
+ let runtime_path = tishlang_build_utils::find_runtime_path_for_project(project_root)?;
44
57
 
45
58
  let runtime_features = runtime_features_for_cargo(features);
46
59
  let runtime_refs: Vec<&str> = runtime_features.iter().map(String::as_str).collect();
@@ -59,12 +72,28 @@ pub fn build_via_cargo(
59
72
 
60
73
  let native_deps: String = native_modules
61
74
  .iter()
75
+ .filter(|m| m.use_path_dependency)
62
76
  .map(|m| {
63
77
  let path = m.crate_path.display().to_string().replace('\\', "/");
64
78
  format!("{} = {{ path = {:?} }}\n", m.package_name, path)
65
79
  })
66
80
  .collect();
67
81
 
82
+ let mut more_deps = String::new();
83
+ more_deps.push_str(&tokio_dep);
84
+ if !native_deps.is_empty() {
85
+ more_deps.push_str(&format!("\n{}", native_deps));
86
+ }
87
+ if !extra_dependencies_toml.trim().is_empty() {
88
+ more_deps.push_str(&format!("\n{}", extra_dependencies_toml));
89
+ }
90
+
91
+ let rust_main = if generated_native_rs.is_some() {
92
+ inject_generated_native_mod(rust_code)
93
+ } else {
94
+ rust_code.to_string()
95
+ };
96
+
68
97
  let tish_ui_path = std::path::Path::new(&runtime_path)
69
98
  .parent()
70
99
  .ok_or_else(|| "invalid tishlang_runtime path (no parent)".to_string())?
@@ -96,23 +125,18 @@ codegen-units = 1
96
125
  lto = "thin"
97
126
 
98
127
  [dependencies]
99
- tishlang_runtime = {{ path = {:?}{} }}{}{}{}
100
- "#,
101
- out_name,
102
- runtime_path,
103
- features_str,
104
- tokio_dep,
105
- if native_deps.is_empty() {
106
- String::new()
107
- } else {
108
- format!("\n{}", native_deps)
109
- },
110
- ui_dep
128
+ tishlang_runtime = {{ path = {:?}{} }}
129
+ {}{}"#,
130
+ out_name, runtime_path, features_str, more_deps, ui_dep
111
131
  );
112
132
 
113
133
  fs::write(build_dir.join("Cargo.toml"), cargo_toml)
114
134
  .map_err(|e| format!("Cannot write Cargo.toml: {}", e))?;
115
- fs::write(build_dir.join("src/main.rs"), rust_code)
135
+ if let Some(gen) = generated_native_rs {
136
+ fs::write(build_dir.join("src/generated_native.rs"), gen)
137
+ .map_err(|e| format!("Cannot write generated_native.rs: {}", e))?;
138
+ }
139
+ fs::write(build_dir.join("src/main.rs"), rust_main)
116
140
  .map_err(|e| format!("Cannot write main.rs: {}", e))?;
117
141
 
118
142
  let workspace_target = Path::new(&runtime_path)
@@ -154,4 +178,3 @@ mod tests {
154
178
  assert_eq!(f.len(), 5);
155
179
  }
156
180
  }
157
-
@@ -57,28 +57,34 @@ pub fn compile_to_native(
57
57
 
58
58
  match backend {
59
59
  Backend::Rust => {
60
- let (rust_code, native_modules, effective_features) = tishlang_compile::compile_project_full(
61
- entry_path,
62
- project_root,
63
- features,
64
- optimize,
65
- )
66
- .map_err(|e| NativeError {
67
- message: e.to_string(),
68
- })?;
60
+ let (rust_code, native_modules, effective_features, native_build) =
61
+ tishlang_compile::compile_project_full(
62
+ entry_path,
63
+ project_root,
64
+ features,
65
+ optimize,
66
+ )
67
+ .map_err(|e| NativeError {
68
+ message: e.to_string(),
69
+ })?;
69
70
 
70
71
  crate::build::build_via_cargo(
71
72
  &rust_code,
72
73
  native_modules,
73
74
  output_path,
74
75
  &effective_features,
76
+ &native_build.rust_dependencies_toml,
77
+ native_build.generated_native_rs.as_deref(),
78
+ project_root,
75
79
  )
76
80
  .map_err(|e| NativeError { message: e })
77
81
  }
78
82
  Backend::Cranelift => {
79
- let modules = tishlang_compile::resolve_project(entry_path, project_root)
80
- .map_err(|e| NativeError {
81
- message: e.to_string(),
83
+ let modules =
84
+ tishlang_compile::resolve_project(entry_path, project_root).map_err(|e| {
85
+ NativeError {
86
+ message: e.to_string(),
87
+ }
82
88
  })?;
83
89
  tishlang_compile::detect_cycles(&modules).map_err(|e| NativeError {
84
90
  message: e.to_string(),
@@ -96,7 +102,7 @@ pub fn compile_to_native(
96
102
 
97
103
  if tishlang_compile::has_external_native_imports(&program) {
98
104
  return Err(NativeError {
99
- message: "Cranelift backend does not support external native imports (tish:egui, @scope/pkg). Built-in tish:fs, tish:http, tish:process are supported. Use --native-backend rust for external modules.".to_string(),
105
+ message: "Cranelift backend does not support external native imports (tish:…, cargo:…, @scope/pkg). Built-in tish:fs, tish:http, tish:process are supported. Use --native-backend rust for external modules.".to_string(),
100
106
  });
101
107
  }
102
108
 
@@ -117,9 +123,15 @@ pub fn compile_to_native(
117
123
  })
118
124
  }
119
125
  Backend::Llvm => {
120
- let modules = tishlang_compile::resolve_project(entry_path, project_root)
121
- .map_err(|e| NativeError { message: e.to_string() })?;
122
- tishlang_compile::detect_cycles(&modules).map_err(|e| NativeError { message: e.to_string() })?;
126
+ let modules =
127
+ tishlang_compile::resolve_project(entry_path, project_root).map_err(|e| {
128
+ NativeError {
129
+ message: e.to_string(),
130
+ }
131
+ })?;
132
+ tishlang_compile::detect_cycles(&modules).map_err(|e| NativeError {
133
+ message: e.to_string(),
134
+ })?;
123
135
  let program = {
124
136
  let prog = tishlang_compile::merge_modules(modules).map_err(|e| NativeError {
125
137
  message: e.to_string(),
@@ -132,7 +144,7 @@ pub fn compile_to_native(
132
144
  };
133
145
  if tishlang_compile::has_external_native_imports(&program) {
134
146
  return Err(NativeError {
135
- message: "LLVM backend does not support external native imports. Built-in tish:fs, tish:http, tish:process are supported.".to_string(),
147
+ message: "LLVM backend does not support external native imports (tish:…, cargo:…, @scope/pkg). Built-in tish:fs, tish:http, tish:process are supported.".to_string(),
136
148
  });
137
149
  }
138
150
  let chunk = if optimize {
@@ -176,10 +188,17 @@ pub fn compile_program_to_native(
176
188
 
177
189
  match backend {
178
190
  Backend::Rust => {
179
- let program = if optimize { tishlang_opt::optimize(program) } else { program.clone() };
191
+ let program = if optimize {
192
+ tishlang_opt::optimize(program)
193
+ } else {
194
+ program.clone()
195
+ };
180
196
  let root = project_root.unwrap_or_else(|| Path::new("."));
181
197
  let native_modules = tishlang_compile::resolve_native_modules(&program, root)
182
198
  .map_err(|e| NativeError { message: e })?;
199
+ let native_build =
200
+ tishlang_compile::compute_native_build_artifacts(&program, root, &native_modules)
201
+ .map_err(|e| NativeError { message: e })?;
183
202
  let mut all_features = features.to_vec();
184
203
  for f in tishlang_compile::extract_native_import_features(&program) {
185
204
  if !all_features.contains(&f) {
@@ -191,41 +210,66 @@ pub fn compile_program_to_native(
191
210
  project_root,
192
211
  &all_features,
193
212
  &native_modules,
213
+ &native_build.native_init,
194
214
  optimize,
195
215
  )
196
- .map_err(|e| NativeError {
197
- message: e.message,
198
- })?;
199
- crate::build::build_via_cargo(&rust_code, native_modules, output_path, &all_features)
200
- .map_err(|e| NativeError { message: e })
216
+ .map_err(|e| NativeError { message: e.message })?;
217
+ crate::build::build_via_cargo(
218
+ &rust_code,
219
+ native_modules,
220
+ output_path,
221
+ &all_features,
222
+ &native_build.rust_dependencies_toml,
223
+ native_build.generated_native_rs.as_deref(),
224
+ Some(root),
225
+ )
226
+ .map_err(|e| NativeError { message: e })
201
227
  }
202
228
  Backend::Cranelift => {
203
229
  if tishlang_compile::has_external_native_imports(program) {
204
230
  return Err(NativeError {
205
- message: "Cranelift backend does not support external native imports. Built-in tish:fs, tish:http, tish:process are supported.".to_string(),
231
+ message: "Cranelift backend does not support external native imports (tish:…, cargo:…, @scope/pkg). Built-in tish:fs, tish:http, tish:process are supported.".to_string(),
206
232
  });
207
233
  }
208
- let program = if optimize { tishlang_opt::optimize(program) } else { program.clone() };
234
+ let program = if optimize {
235
+ tishlang_opt::optimize(program)
236
+ } else {
237
+ program.clone()
238
+ };
209
239
  let chunk = if optimize {
210
- tishlang_bytecode::compile(&program).map_err(|e| NativeError { message: e.to_string() })?
240
+ tishlang_bytecode::compile(&program).map_err(|e| NativeError {
241
+ message: e.to_string(),
242
+ })?
211
243
  } else {
212
- tishlang_bytecode::compile_unoptimized(&program).map_err(|e| NativeError { message: e.to_string() })?
244
+ tishlang_bytecode::compile_unoptimized(&program).map_err(|e| NativeError {
245
+ message: e.to_string(),
246
+ })?
213
247
  };
214
248
  let cranelift_features = tishlang_compile::extract_native_import_features(&program);
215
249
  tishlang_cranelift::compile_chunk_to_native(&chunk, output_path, &cranelift_features)
216
- .map_err(|e| NativeError { message: e.to_string() })
250
+ .map_err(|e| NativeError {
251
+ message: e.to_string(),
252
+ })
217
253
  }
218
254
  Backend::Llvm => {
219
255
  if tishlang_compile::has_external_native_imports(program) {
220
256
  return Err(NativeError {
221
- message: "LLVM backend does not support external native imports.".to_string(),
257
+ message: "LLVM backend does not support external native imports (tish:…, cargo:…, @scope/pkg).".to_string(),
222
258
  });
223
259
  }
224
- let program = if optimize { tishlang_opt::optimize(program) } else { program.clone() };
260
+ let program = if optimize {
261
+ tishlang_opt::optimize(program)
262
+ } else {
263
+ program.clone()
264
+ };
225
265
  let chunk = if optimize {
226
- tishlang_bytecode::compile(&program).map_err(|e| NativeError { message: e.to_string() })?
266
+ tishlang_bytecode::compile(&program).map_err(|e| NativeError {
267
+ message: e.to_string(),
268
+ })?
227
269
  } else {
228
- tishlang_bytecode::compile_unoptimized(&program).map_err(|e| NativeError { message: e.to_string() })?
270
+ tishlang_bytecode::compile_unoptimized(&program).map_err(|e| NativeError {
271
+ message: e.to_string(),
272
+ })?
229
273
  };
230
274
  let llvm_features = tishlang_compile::extract_native_import_features(&program);
231
275
  tishlang_llvm::compile_chunk_to_native(&chunk, output_path, &llvm_features)
@@ -10,11 +10,7 @@ use tishlang_ast::{ArrowBody, BinOp, Expr, Literal, Program, Statement, UnaryOp}
10
10
  /// Optimize a Tish program. Returns a new program with transformations applied.
11
11
  pub fn optimize(program: &Program) -> Program {
12
12
  Program {
13
- statements: program
14
- .statements
15
- .iter()
16
- .map(optimize_statement)
17
- .collect(),
13
+ statements: program.statements.iter().map(optimize_statement).collect(),
18
14
  }
19
15
  }
20
16
 
@@ -79,7 +75,9 @@ fn optimize_statement(stmt: &Statement) -> Statement {
79
75
  Statement::If {
80
76
  cond: opt_cond,
81
77
  then_branch: Box::new(optimize_statement(then_branch)),
82
- else_branch: else_branch.as_ref().map(|b| Box::new(optimize_statement(b))),
78
+ else_branch: else_branch
79
+ .as_ref()
80
+ .map(|b| Box::new(optimize_statement(b))),
83
81
  span: *span,
84
82
  }
85
83
  }
@@ -144,21 +142,12 @@ fn optimize_statement(stmt: &Statement) -> Statement {
144
142
  expr: optimize_expr(expr),
145
143
  cases: cases
146
144
  .iter()
147
- .map(|(ce, stmts)| {
148
- (
149
- ce.as_ref().map(optimize_expr),
150
- optimize_block(stmts),
151
- )
152
- })
145
+ .map(|(ce, stmts)| (ce.as_ref().map(optimize_expr), optimize_block(stmts)))
153
146
  .collect(),
154
147
  default_body: default_body.as_ref().map(|stmts| optimize_block(stmts)),
155
148
  span: *span,
156
149
  },
157
- Statement::DoWhile {
158
- body,
159
- cond,
160
- span,
161
- } => Statement::DoWhile {
150
+ Statement::DoWhile { body, cond, span } => Statement::DoWhile {
162
151
  body: Box::new(optimize_statement(body)),
163
152
  cond: optimize_expr(cond),
164
153
  span: *span,
@@ -177,7 +166,9 @@ fn optimize_statement(stmt: &Statement) -> Statement {
177
166
  body: Box::new(optimize_statement(body)),
178
167
  catch_param: catch_param.clone(),
179
168
  catch_body: catch_body.as_ref().map(|b| Box::new(optimize_statement(b))),
180
- finally_body: finally_body.as_ref().map(|b| Box::new(optimize_statement(b))),
169
+ finally_body: finally_body
170
+ .as_ref()
171
+ .map(|b| Box::new(optimize_statement(b))),
181
172
  span: *span,
182
173
  },
183
174
  Statement::Import { .. } | Statement::Export { .. } => stmt.clone(),
@@ -232,7 +223,12 @@ fn optimize_expr(expr: &Expr) -> Expr {
232
223
  name: Arc::clone(name),
233
224
  span: *span,
234
225
  },
235
- Expr::Binary { left, op, right, span } => {
226
+ Expr::Binary {
227
+ left,
228
+ op,
229
+ right,
230
+ span,
231
+ } => {
236
232
  let opt_left = optimize_expr(left);
237
233
  let opt_right = optimize_expr(right);
238
234
 
@@ -324,32 +320,28 @@ fn optimize_expr(expr: &Expr) -> Expr {
324
320
  span: *span,
325
321
  }
326
322
  }
327
- Expr::Call {
328
- callee,
329
- args,
330
- span,
331
- } => Expr::Call {
323
+ Expr::Call { callee, args, span } => Expr::Call {
332
324
  callee: Box::new(optimize_expr(callee)),
333
325
  args: args
334
326
  .iter()
335
327
  .map(|a| match a {
336
328
  tishlang_ast::CallArg::Expr(e) => tishlang_ast::CallArg::Expr(optimize_expr(e)),
337
- tishlang_ast::CallArg::Spread(e) => tishlang_ast::CallArg::Spread(optimize_expr(e)),
329
+ tishlang_ast::CallArg::Spread(e) => {
330
+ tishlang_ast::CallArg::Spread(optimize_expr(e))
331
+ }
338
332
  })
339
333
  .collect(),
340
334
  span: *span,
341
335
  },
342
- Expr::New {
343
- callee,
344
- args,
345
- span,
346
- } => Expr::New {
336
+ Expr::New { callee, args, span } => Expr::New {
347
337
  callee: Box::new(optimize_expr(callee)),
348
338
  args: args
349
339
  .iter()
350
340
  .map(|a| match a {
351
341
  tishlang_ast::CallArg::Expr(e) => tishlang_ast::CallArg::Expr(optimize_expr(e)),
352
- tishlang_ast::CallArg::Spread(e) => tishlang_ast::CallArg::Spread(optimize_expr(e)),
342
+ tishlang_ast::CallArg::Spread(e) => {
343
+ tishlang_ast::CallArg::Spread(optimize_expr(e))
344
+ }
353
345
  })
354
346
  .collect(),
355
347
  span: *span,
@@ -385,14 +377,11 @@ fn optimize_expr(expr: &Expr) -> Expr {
385
377
  optional: *optional,
386
378
  span: *span,
387
379
  },
388
- Expr::NullishCoalesce {
389
- left,
390
- right,
391
- span,
392
- } => {
380
+ Expr::NullishCoalesce { left, right, span } => {
393
381
  let opt_left = optimize_expr(left);
394
382
  if let Expr::Literal {
395
- value: Literal::Null, ..
383
+ value: Literal::Null,
384
+ ..
396
385
  } = &opt_left
397
386
  {
398
387
  return optimize_expr(right);
@@ -444,13 +433,23 @@ fn optimize_expr(expr: &Expr) -> Expr {
444
433
  | Expr::PostfixDec { .. }
445
434
  | Expr::PrefixInc { .. }
446
435
  | Expr::PrefixDec { .. } => expr.clone(),
447
- Expr::CompoundAssign { name, op, value, span } => Expr::CompoundAssign {
436
+ Expr::CompoundAssign {
437
+ name,
438
+ op,
439
+ value,
440
+ span,
441
+ } => Expr::CompoundAssign {
448
442
  name: Arc::clone(name),
449
443
  op: *op,
450
444
  value: Box::new(optimize_expr(value)),
451
445
  span: *span,
452
446
  },
453
- Expr::LogicalAssign { name, op, value, span } => Expr::LogicalAssign {
447
+ Expr::LogicalAssign {
448
+ name,
449
+ op,
450
+ value,
451
+ span,
452
+ } => Expr::LogicalAssign {
454
453
  name: Arc::clone(name),
455
454
  op: *op,
456
455
  value: Box::new(optimize_expr(value)),
@@ -478,11 +477,7 @@ fn optimize_expr(expr: &Expr) -> Expr {
478
477
  value: Box::new(optimize_expr(value)),
479
478
  span: *span,
480
479
  },
481
- Expr::ArrowFunction {
482
- params,
483
- body,
484
- span,
485
- } => {
480
+ Expr::ArrowFunction { params, body, span } => {
486
481
  let opt_body = match body {
487
482
  ArrowBody::Expr(e) => ArrowBody::Expr(Box::new(optimize_expr(e))),
488
483
  ArrowBody::Block(s) => ArrowBody::Block(Box::new(optimize_statement(s))),
@@ -493,7 +488,11 @@ fn optimize_expr(expr: &Expr) -> Expr {
493
488
  span: *span,
494
489
  }
495
490
  }
496
- Expr::TemplateLiteral { quasis, exprs, span } => Expr::TemplateLiteral {
491
+ Expr::TemplateLiteral {
492
+ quasis,
493
+ exprs,
494
+ span,
495
+ } => Expr::TemplateLiteral {
497
496
  quasis: quasis.iter().map(Arc::clone).collect(),
498
497
  exprs: exprs.iter().map(optimize_expr).collect(),
499
498
  span: *span,
@@ -503,7 +502,11 @@ fn optimize_expr(expr: &Expr) -> Expr {
503
502
  span: *span,
504
503
  },
505
504
  Expr::JsxElement { .. } | Expr::JsxFragment { .. } => expr.clone(),
506
- Expr::NativeModuleLoad { spec, export_name, span } => Expr::NativeModuleLoad {
505
+ Expr::NativeModuleLoad {
506
+ spec,
507
+ export_name,
508
+ span,
509
+ } => Expr::NativeModuleLoad {
507
510
  spec: Arc::clone(spec),
508
511
  export_name: Arc::clone(export_name),
509
512
  span: *span,
@@ -699,8 +702,12 @@ fn try_fold_binop(left: &Literal, op: BinOp, right: &Literal) -> Option<Literal>
699
702
  Add => {
700
703
  if matches!(left, Literal::String(_)) || matches!(right, Literal::String(_)) {
701
704
  return Some(Literal::String(
702
- format!("{}{}", literal_to_display_string(left), literal_to_display_string(right))
703
- .into(),
705
+ format!(
706
+ "{}{}",
707
+ literal_to_display_string(left),
708
+ literal_to_display_string(right)
709
+ )
710
+ .into(),
704
711
  ));
705
712
  }
706
713
  Literal::Number(ln + rn)
@@ -769,7 +776,11 @@ mod tests {
769
776
  [tishlang_ast::Statement::ExprStmt { expr, .. }] => expr,
770
777
  _ => panic!("expected single expr stmt"),
771
778
  };
772
- assert!(has_literal_number(expr, -42.0), "expected -42, got {:?}", expr);
779
+ assert!(
780
+ has_literal_number(expr, -42.0),
781
+ "expected -42, got {:?}",
782
+ expr
783
+ );
773
784
  }
774
785
 
775
786
  #[test]
@@ -781,7 +792,13 @@ mod tests {
781
792
  _ => panic!("expected single expr stmt"),
782
793
  };
783
794
  assert!(
784
- matches!(expr, Expr::Literal { value: Literal::Bool(false), .. }),
795
+ matches!(
796
+ expr,
797
+ Expr::Literal {
798
+ value: Literal::Bool(false),
799
+ ..
800
+ }
801
+ ),
785
802
  "expected false, got {:?}",
786
803
  expr
787
804
  );
@@ -38,7 +38,9 @@ mod tests {
38
38
  assert_eq!(program.statements.len(), 1);
39
39
  let stmt = &program.statements[0];
40
40
  let init = match stmt {
41
- Statement::VarDecl { init: Some(ref i), .. } => i,
41
+ Statement::VarDecl {
42
+ init: Some(ref i), ..
43
+ } => i,
42
44
  _ => panic!("expected VarDecl with init"),
43
45
  };
44
46
  let props = match init {
@@ -61,11 +63,14 @@ mod tests {
61
63
 
62
64
  #[test]
63
65
  fn test_object_literal_string_key() {
64
- let program = parse(r#"const o = { "ai-a": 0, human: 1 }"#).expect("parse object with string key");
66
+ let program =
67
+ parse(r#"const o = { "ai-a": 0, human: 1 }"#).expect("parse object with string key");
65
68
  assert_eq!(program.statements.len(), 1);
66
69
  let stmt = &program.statements[0];
67
70
  let init = match stmt {
68
- Statement::VarDecl { init: Some(ref i), .. } => i,
71
+ Statement::VarDecl {
72
+ init: Some(ref i), ..
73
+ } => i,
69
74
  _ => panic!("expected VarDecl with init"),
70
75
  };
71
76
  let props = match init {
@@ -89,7 +94,9 @@ mod tests {
89
94
  assert_eq!(program.statements.len(), 1);
90
95
  let stmt = &program.statements[0];
91
96
  let init = match stmt {
92
- Statement::VarDecl { init: Some(ref i), .. } => i,
97
+ Statement::VarDecl {
98
+ init: Some(ref i), ..
99
+ } => i,
93
100
  _ => panic!("expected VarDecl with init"),
94
101
  };
95
102
  let props = match init {
@@ -134,7 +141,9 @@ mod tests {
134
141
  let e = unwrap_expr_stmt(&program);
135
142
  match e {
136
143
  Expr::New { callee, args, .. } => {
137
- assert!(matches!(callee.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Foo"));
144
+ assert!(
145
+ matches!(callee.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Foo")
146
+ );
138
147
  assert!(args.is_empty());
139
148
  }
140
149
  _ => panic!("expected New, got {:?}", e),
@@ -147,7 +156,9 @@ mod tests {
147
156
  let e = unwrap_expr_stmt(&program);
148
157
  match e {
149
158
  Expr::New { callee, args, .. } => {
150
- assert!(matches!(callee.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Uint8Array"));
159
+ assert!(
160
+ matches!(callee.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Uint8Array")
161
+ );
151
162
  assert_eq!(args.len(), 1);
152
163
  assert!(matches!(&args[0], CallArg::Expr(Expr::Literal { .. })));
153
164
  }
@@ -179,8 +190,14 @@ mod tests {
179
190
  Expr::New { callee, args, .. } => {
180
191
  assert!(args.is_empty());
181
192
  match callee.as_ref() {
182
- Expr::New { callee: inner, args: inner_args, .. } => {
183
- assert!(matches!(inner.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Date"));
193
+ Expr::New {
194
+ callee: inner,
195
+ args: inner_args,
196
+ ..
197
+ } => {
198
+ assert!(
199
+ matches!(inner.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Date")
200
+ );
184
201
  assert!(inner_args.is_empty());
185
202
  }
186
203
  _ => panic!("expected nested New"),
@@ -195,11 +212,17 @@ mod tests {
195
212
  let program = parse("new Foo().bar").expect("parse");
196
213
  let e = unwrap_expr_stmt(&program);
197
214
  match e {
198
- Expr::Member { object, prop: tishlang_ast::MemberProp::Name(p), .. } => {
215
+ Expr::Member {
216
+ object,
217
+ prop: tishlang_ast::MemberProp::Name(p),
218
+ ..
219
+ } => {
199
220
  assert_eq!(p.as_ref(), "bar");
200
221
  match object.as_ref() {
201
222
  Expr::New { callee, args, .. } => {
202
- assert!(matches!(callee.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Foo"));
223
+ assert!(
224
+ matches!(callee.as_ref(), Expr::Ident { name, .. } if name.as_ref() == "Foo")
225
+ );
203
226
  assert!(args.is_empty());
204
227
  }
205
228
  _ => panic!("expected New object"),
@@ -215,7 +238,9 @@ mod tests {
215
238
  let e = unwrap_expr_stmt(&program);
216
239
  match e {
217
240
  Expr::New { args, .. } => {
218
- assert!(matches!(&args[0], CallArg::Spread(Expr::Ident { name, .. }) if name.as_ref() == "xs"));
241
+ assert!(
242
+ matches!(&args[0], CallArg::Spread(Expr::Ident { name, .. }) if name.as_ref() == "xs")
243
+ );
219
244
  }
220
245
  _ => panic!("expected New"),
221
246
  }