@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.
- package/Cargo.toml +1 -0
- package/bin/tish +0 -0
- package/crates/js_to_tish/src/error.rs +2 -8
- package/crates/js_to_tish/src/transform/expr.rs +101 -130
- package/crates/js_to_tish/src/transform/stmt.rs +25 -22
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cli_help.rs +76 -29
- package/crates/tish/src/main.rs +85 -54
- package/crates/tish/tests/cargo_example_compile.rs +67 -0
- package/crates/tish/tests/fixtures/cargo_example_project/Cargo.toml +3 -0
- package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/Cargo.toml +11 -0
- package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/src/lib.rs +12 -0
- package/crates/tish/tests/fixtures/cargo_example_project/package.json +10 -0
- package/crates/tish/tests/fixtures/cargo_example_project/src/main.tish +3 -0
- package/crates/tish/tests/integration_test.rs +197 -47
- package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
- package/crates/tish/tests/shortcircuit.rs +19 -4
- package/crates/tish_ast/src/ast.rs +12 -14
- package/crates/tish_build_utils/src/lib.rs +64 -6
- package/crates/tish_builtins/src/array.rs +52 -21
- package/crates/tish_builtins/src/construct.rs +2 -8
- package/crates/tish_builtins/src/globals.rs +30 -15
- package/crates/tish_builtins/src/lib.rs +5 -5
- package/crates/tish_builtins/src/math.rs +5 -3
- package/crates/tish_builtins/src/string.rs +71 -19
- package/crates/tish_bytecode/src/chunk.rs +0 -1
- package/crates/tish_bytecode/src/compiler.rs +164 -60
- package/crates/tish_bytecode/src/opcode.rs +13 -4
- package/crates/tish_bytecode/src/peephole.rs +2 -2
- package/crates/tish_compile/Cargo.toml +1 -0
- package/crates/tish_compile/src/codegen.rs +989 -318
- package/crates/tish_compile/src/infer.rs +69 -19
- package/crates/tish_compile/src/lib.rs +21 -8
- package/crates/tish_compile/src/resolve.rs +515 -94
- package/crates/tish_compile/src/types.rs +10 -14
- package/crates/tish_compile_js/src/codegen.rs +34 -13
- package/crates/tish_compile_js/src/tests_jsx.rs +30 -6
- package/crates/tish_compiler_wasm/src/lib.rs +16 -13
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +40 -48
- package/crates/tish_core/src/json.rs +5 -3
- package/crates/tish_core/src/lib.rs +1 -1
- package/crates/tish_core/src/uri.rs +9 -6
- package/crates/tish_core/src/value.rs +92 -28
- package/crates/tish_cranelift/src/link.rs +6 -9
- package/crates/tish_cranelift/src/lower.rs +14 -8
- package/crates/tish_eval/src/eval.rs +398 -141
- package/crates/tish_eval/src/lib.rs +10 -6
- package/crates/tish_eval/src/natives.rs +95 -38
- package/crates/tish_eval/src/promise.rs +14 -8
- package/crates/tish_eval/src/timers.rs +28 -19
- package/crates/tish_eval/src/value.rs +10 -3
- package/crates/tish_fmt/src/lib.rs +29 -13
- package/crates/tish_lexer/src/lib.rs +217 -63
- package/crates/tish_lexer/src/token.rs +6 -6
- package/crates/tish_llvm/src/lib.rs +15 -8
- package/crates/tish_lsp/src/main.rs +41 -43
- package/crates/tish_native/src/build.rs +38 -15
- package/crates/tish_native/src/lib.rs +76 -32
- package/crates/tish_opt/src/lib.rs +67 -50
- package/crates/tish_parser/src/lib.rs +36 -11
- package/crates/tish_parser/src/parser.rs +172 -87
- package/crates/tish_runtime/src/http.rs +15 -6
- package/crates/tish_runtime/src/http_fetch.rs +24 -14
- package/crates/tish_runtime/src/lib.rs +224 -168
- package/crates/tish_runtime/src/promise.rs +1 -5
- package/crates/tish_runtime/src/ws.rs +45 -20
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
- package/crates/tish_ui/src/jsx.rs +41 -22
- package/crates/tish_ui/src/lib.rs +2 -2
- package/crates/tish_vm/src/vm.rs +320 -116
- package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +8 -3
- package/crates/tish_wasm/src/lib.rs +38 -28
- package/crates/tishlang_cargo_bindgen/Cargo.toml +25 -0
- package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
- package/crates/tishlang_cargo_bindgen/src/discover.rs +52 -0
- package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
- package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
- package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -0
- package/package.json +1 -1
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- 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::
|
|
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
|
-
|
|
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) =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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 =
|
|
80
|
-
.map_err(|e|
|
|
81
|
-
|
|
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
|
|
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 =
|
|
121
|
-
.map_err(|e|
|
|
122
|
-
|
|
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 {
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
|
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
|
|
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 {
|
|
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) =>
|
|
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) =>
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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!(
|
|
703
|
-
|
|
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!(
|
|
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!(
|
|
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 {
|
|
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 =
|
|
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 {
|
|
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 {
|
|
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!(
|
|
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!(
|
|
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 {
|
|
183
|
-
|
|
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 {
|
|
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!(
|
|
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!(
|
|
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
|
}
|