@tishlang/tish 1.0.7 → 1.0.10
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 +43 -0
- package/LICENSE +13 -0
- package/README.md +66 -0
- package/crates/js_to_tish/Cargo.toml +9 -0
- package/crates/js_to_tish/README.md +18 -0
- package/crates/js_to_tish/src/error.rs +61 -0
- package/crates/js_to_tish/src/lib.rs +11 -0
- package/crates/js_to_tish/src/span_util.rs +35 -0
- package/crates/js_to_tish/src/transform/expr.rs +608 -0
- package/crates/js_to_tish/src/transform/stmt.rs +474 -0
- package/crates/js_to_tish/src/transform.rs +60 -0
- package/crates/tish/Cargo.toml +44 -0
- package/crates/tish/src/main.rs +585 -0
- package/crates/tish/src/repl_completion.rs +200 -0
- package/crates/tish/tests/integration_test.rs +726 -0
- package/crates/tish_ast/Cargo.toml +7 -0
- package/crates/tish_ast/src/ast.rs +494 -0
- package/crates/tish_ast/src/lib.rs +5 -0
- package/crates/tish_build_utils/Cargo.toml +5 -0
- package/crates/tish_build_utils/src/lib.rs +175 -0
- package/crates/tish_builtins/Cargo.toml +12 -0
- package/crates/tish_builtins/src/array.rs +410 -0
- package/crates/tish_builtins/src/globals.rs +197 -0
- package/crates/tish_builtins/src/helpers.rs +38 -0
- package/crates/tish_builtins/src/lib.rs +14 -0
- package/crates/tish_builtins/src/math.rs +80 -0
- package/crates/tish_builtins/src/object.rs +36 -0
- package/crates/tish_builtins/src/string.rs +253 -0
- package/crates/tish_bytecode/Cargo.toml +15 -0
- package/crates/tish_bytecode/src/chunk.rs +97 -0
- package/crates/tish_bytecode/src/compiler.rs +1361 -0
- package/crates/tish_bytecode/src/encoding.rs +100 -0
- package/crates/tish_bytecode/src/lib.rs +19 -0
- package/crates/tish_bytecode/src/opcode.rs +110 -0
- package/crates/tish_bytecode/src/peephole.rs +159 -0
- package/crates/tish_bytecode/src/serialize.rs +163 -0
- package/crates/tish_bytecode/tests/constant_folding.rs +84 -0
- package/crates/tish_bytecode/tests/shortcircuit.rs +49 -0
- package/crates/tish_bytecode/tests/sort_optimization.rs +31 -0
- package/crates/tish_compile/Cargo.toml +21 -0
- package/crates/tish_compile/src/codegen.rs +3316 -0
- package/crates/tish_compile/src/lib.rs +71 -0
- package/crates/tish_compile/src/resolve.rs +631 -0
- package/crates/tish_compile/src/types.rs +304 -0
- package/crates/tish_compile_js/Cargo.toml +16 -0
- package/crates/tish_compile_js/examples/jsx_vdom_smoke.tish +8 -0
- package/crates/tish_compile_js/src/codegen.rs +794 -0
- package/crates/tish_compile_js/src/error.rs +20 -0
- package/crates/tish_compile_js/src/js_intrinsics.rs +82 -0
- package/crates/tish_compile_js/src/lib.rs +27 -0
- package/crates/tish_compile_js/src/tests_jsx.rs +32 -0
- package/crates/tish_compiler_wasm/Cargo.toml +19 -0
- package/crates/tish_compiler_wasm/src/lib.rs +55 -0
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +462 -0
- package/crates/tish_core/Cargo.toml +11 -0
- package/crates/tish_core/src/console_style.rs +128 -0
- package/crates/tish_core/src/json.rs +327 -0
- package/crates/tish_core/src/lib.rs +15 -0
- package/crates/tish_core/src/macros.rs +37 -0
- package/crates/tish_core/src/uri.rs +115 -0
- package/crates/tish_core/src/value.rs +376 -0
- package/crates/tish_cranelift/Cargo.toml +17 -0
- package/crates/tish_cranelift/src/lib.rs +41 -0
- package/crates/tish_cranelift/src/link.rs +120 -0
- package/crates/tish_cranelift/src/lower.rs +77 -0
- package/crates/tish_cranelift_runtime/Cargo.toml +19 -0
- package/crates/tish_cranelift_runtime/src/lib.rs +43 -0
- package/crates/tish_eval/Cargo.toml +26 -0
- package/crates/tish_eval/src/eval.rs +3205 -0
- package/crates/tish_eval/src/http.rs +122 -0
- package/crates/tish_eval/src/lib.rs +59 -0
- package/crates/tish_eval/src/natives.rs +301 -0
- package/crates/tish_eval/src/promise.rs +173 -0
- package/crates/tish_eval/src/regex.rs +298 -0
- package/crates/tish_eval/src/timers.rs +111 -0
- package/crates/tish_eval/src/value.rs +224 -0
- package/crates/tish_eval/src/value_convert.rs +85 -0
- package/crates/tish_fmt/Cargo.toml +16 -0
- package/crates/tish_fmt/src/bin/tish-fmt.rs +41 -0
- package/crates/tish_fmt/src/lib.rs +884 -0
- package/crates/tish_jsx_web/Cargo.toml +7 -0
- package/crates/tish_jsx_web/README.md +18 -0
- package/crates/tish_jsx_web/src/lib.rs +157 -0
- package/crates/tish_jsx_web/vendor/Lattish.tish +347 -0
- package/crates/tish_lexer/Cargo.toml +7 -0
- package/crates/tish_lexer/src/lib.rs +430 -0
- package/crates/tish_lexer/src/token.rs +155 -0
- package/crates/tish_lint/Cargo.toml +17 -0
- package/crates/tish_lint/src/bin/tish-lint.rs +77 -0
- package/crates/tish_lint/src/lib.rs +278 -0
- package/crates/tish_llvm/Cargo.toml +11 -0
- package/crates/tish_llvm/src/lib.rs +106 -0
- package/crates/tish_lsp/Cargo.toml +22 -0
- package/crates/tish_lsp/README.md +26 -0
- package/crates/tish_lsp/src/main.rs +615 -0
- package/crates/tish_native/Cargo.toml +14 -0
- package/crates/tish_native/src/build.rs +102 -0
- package/crates/tish_native/src/lib.rs +237 -0
- package/crates/tish_opt/Cargo.toml +11 -0
- package/crates/tish_opt/src/lib.rs +896 -0
- package/crates/tish_parser/Cargo.toml +9 -0
- package/crates/tish_parser/src/lib.rs +123 -0
- package/crates/tish_parser/src/parser.rs +1714 -0
- package/crates/tish_runtime/Cargo.toml +26 -0
- package/crates/tish_runtime/src/http.rs +308 -0
- package/crates/tish_runtime/src/http_fetch.rs +453 -0
- package/crates/tish_runtime/src/lib.rs +1004 -0
- package/crates/tish_runtime/src/native_promise.rs +26 -0
- package/crates/tish_runtime/src/promise.rs +77 -0
- package/crates/tish_runtime/src/promise_io.rs +41 -0
- package/crates/tish_runtime/src/timers.rs +125 -0
- package/crates/tish_runtime/src/ws.rs +725 -0
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +99 -0
- package/crates/tish_vm/Cargo.toml +31 -0
- package/crates/tish_vm/src/lib.rs +39 -0
- package/crates/tish_vm/src/vm.rs +1399 -0
- package/crates/tish_wasm/Cargo.toml +13 -0
- package/crates/tish_wasm/src/lib.rs +358 -0
- package/crates/tish_wasm_runtime/Cargo.toml +25 -0
- package/crates/tish_wasm_runtime/src/lib.rs +36 -0
- package/justfile +260 -0
- package/package.json +8 -3
- 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
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
//! Abstract syntax tree for Tish.
|
|
2
|
+
|
|
3
|
+
use std::sync::Arc;
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
6
|
+
pub struct Span {
|
|
7
|
+
pub start: (usize, usize), // line, col
|
|
8
|
+
pub end: (usize, usize),
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/// Type annotation for variables, parameters, and return types.
|
|
12
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
13
|
+
pub enum TypeAnnotation {
|
|
14
|
+
/// Primitive types: number, string, boolean, null
|
|
15
|
+
Simple(Arc<str>),
|
|
16
|
+
/// Array type: T[]
|
|
17
|
+
Array(Box<TypeAnnotation>),
|
|
18
|
+
/// Object type: { key: Type, ... }
|
|
19
|
+
Object(Vec<(Arc<str>, TypeAnnotation)>),
|
|
20
|
+
/// Function type: (T1, T2) => R
|
|
21
|
+
Function {
|
|
22
|
+
params: Vec<TypeAnnotation>,
|
|
23
|
+
returns: Box<TypeAnnotation>,
|
|
24
|
+
},
|
|
25
|
+
/// Union type: T1 | T2
|
|
26
|
+
Union(Vec<TypeAnnotation>),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// Function parameter with optional type annotation and default value.
|
|
30
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
31
|
+
pub struct TypedParam {
|
|
32
|
+
pub name: Arc<str>,
|
|
33
|
+
pub type_ann: Option<TypeAnnotation>,
|
|
34
|
+
pub default: Option<Expr>,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Destructuring pattern for array or object destructuring
|
|
38
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
39
|
+
pub enum DestructPattern {
|
|
40
|
+
/// Array destructuring: [a, b, c] or [a, , c]
|
|
41
|
+
Array(Vec<Option<DestructElement>>),
|
|
42
|
+
/// Object destructuring: { a, b: renamed, c }
|
|
43
|
+
Object(Vec<DestructProp>),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// Element in array destructuring pattern
|
|
47
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
48
|
+
pub enum DestructElement {
|
|
49
|
+
/// Simple binding: a
|
|
50
|
+
Ident(Arc<str>),
|
|
51
|
+
/// Nested pattern: [a, b] or { x, y }
|
|
52
|
+
Pattern(Box<DestructPattern>),
|
|
53
|
+
/// Rest element: ...rest
|
|
54
|
+
Rest(Arc<str>),
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Property in object destructuring pattern
|
|
58
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
59
|
+
pub struct DestructProp {
|
|
60
|
+
/// Original property name in source object
|
|
61
|
+
pub key: Arc<str>,
|
|
62
|
+
/// Binding name (may be same as key or renamed)
|
|
63
|
+
pub value: DestructElement,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Import specifier: named (a, b: c), namespace (* as M), or default (X)
|
|
67
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
68
|
+
pub enum ImportSpecifier {
|
|
69
|
+
/// Named: { foo } or { foo as bar }
|
|
70
|
+
Named { name: Arc<str>, alias: Option<Arc<str>> },
|
|
71
|
+
/// Namespace: * as M
|
|
72
|
+
Namespace(Arc<str>),
|
|
73
|
+
/// Default: import X from "..."
|
|
74
|
+
Default(Arc<str>),
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// Export declaration: named (const/let/fn) or default
|
|
78
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
79
|
+
pub enum ExportDeclaration {
|
|
80
|
+
/// export const x = 1 / export let x / export fn f() {}
|
|
81
|
+
Named(Box<Statement>),
|
|
82
|
+
/// export default expr
|
|
83
|
+
Default(Expr),
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#[derive(Debug, Clone)]
|
|
87
|
+
pub struct Program {
|
|
88
|
+
pub statements: Vec<Statement>,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
92
|
+
pub enum Statement {
|
|
93
|
+
Block {
|
|
94
|
+
statements: Vec<Statement>,
|
|
95
|
+
span: Span,
|
|
96
|
+
},
|
|
97
|
+
VarDecl {
|
|
98
|
+
name: Arc<str>,
|
|
99
|
+
mutable: bool, // true for `let`, false for `const`
|
|
100
|
+
type_ann: Option<TypeAnnotation>,
|
|
101
|
+
init: Option<Expr>,
|
|
102
|
+
span: Span,
|
|
103
|
+
},
|
|
104
|
+
/// Variable declaration with destructuring pattern
|
|
105
|
+
VarDeclDestructure {
|
|
106
|
+
pattern: DestructPattern,
|
|
107
|
+
mutable: bool,
|
|
108
|
+
init: Expr,
|
|
109
|
+
span: Span,
|
|
110
|
+
},
|
|
111
|
+
ExprStmt {
|
|
112
|
+
expr: Expr,
|
|
113
|
+
span: Span,
|
|
114
|
+
},
|
|
115
|
+
If {
|
|
116
|
+
cond: Expr,
|
|
117
|
+
then_branch: Box<Statement>,
|
|
118
|
+
else_branch: Option<Box<Statement>>,
|
|
119
|
+
span: Span,
|
|
120
|
+
},
|
|
121
|
+
While {
|
|
122
|
+
cond: Expr,
|
|
123
|
+
body: Box<Statement>,
|
|
124
|
+
span: Span,
|
|
125
|
+
},
|
|
126
|
+
For {
|
|
127
|
+
init: Option<Box<Statement>>,
|
|
128
|
+
cond: Option<Expr>,
|
|
129
|
+
update: Option<Expr>,
|
|
130
|
+
body: Box<Statement>,
|
|
131
|
+
span: Span,
|
|
132
|
+
},
|
|
133
|
+
ForOf {
|
|
134
|
+
name: Arc<str>,
|
|
135
|
+
iterable: Expr,
|
|
136
|
+
body: Box<Statement>,
|
|
137
|
+
span: Span,
|
|
138
|
+
},
|
|
139
|
+
Return {
|
|
140
|
+
value: Option<Expr>,
|
|
141
|
+
span: Span,
|
|
142
|
+
},
|
|
143
|
+
Break {
|
|
144
|
+
span: Span,
|
|
145
|
+
},
|
|
146
|
+
Continue {
|
|
147
|
+
span: Span,
|
|
148
|
+
},
|
|
149
|
+
FunDecl {
|
|
150
|
+
async_: bool,
|
|
151
|
+
name: Arc<str>,
|
|
152
|
+
params: Vec<TypedParam>,
|
|
153
|
+
rest_param: Option<TypedParam>,
|
|
154
|
+
return_type: Option<TypeAnnotation>,
|
|
155
|
+
body: Box<Statement>,
|
|
156
|
+
span: Span,
|
|
157
|
+
},
|
|
158
|
+
Switch {
|
|
159
|
+
expr: Expr,
|
|
160
|
+
cases: Vec<(Option<Expr>, Vec<Statement>)>,
|
|
161
|
+
default_body: Option<Vec<Statement>>,
|
|
162
|
+
span: Span,
|
|
163
|
+
},
|
|
164
|
+
DoWhile {
|
|
165
|
+
body: Box<Statement>,
|
|
166
|
+
cond: Expr,
|
|
167
|
+
span: Span,
|
|
168
|
+
},
|
|
169
|
+
Throw {
|
|
170
|
+
value: Expr,
|
|
171
|
+
span: Span,
|
|
172
|
+
},
|
|
173
|
+
Try {
|
|
174
|
+
body: Box<Statement>,
|
|
175
|
+
catch_param: Option<Arc<str>>,
|
|
176
|
+
catch_body: Option<Box<Statement>>,
|
|
177
|
+
finally_body: Option<Box<Statement>>,
|
|
178
|
+
span: Span,
|
|
179
|
+
},
|
|
180
|
+
Import {
|
|
181
|
+
specifiers: Vec<ImportSpecifier>,
|
|
182
|
+
from: Arc<str>,
|
|
183
|
+
span: Span,
|
|
184
|
+
},
|
|
185
|
+
Export {
|
|
186
|
+
declaration: Box<ExportDeclaration>,
|
|
187
|
+
span: Span,
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
192
|
+
pub enum Expr {
|
|
193
|
+
Literal {
|
|
194
|
+
value: Literal,
|
|
195
|
+
span: Span,
|
|
196
|
+
},
|
|
197
|
+
Ident {
|
|
198
|
+
name: Arc<str>,
|
|
199
|
+
span: Span,
|
|
200
|
+
},
|
|
201
|
+
Binary {
|
|
202
|
+
left: Box<Expr>,
|
|
203
|
+
op: BinOp,
|
|
204
|
+
right: Box<Expr>,
|
|
205
|
+
span: Span,
|
|
206
|
+
},
|
|
207
|
+
Unary {
|
|
208
|
+
op: UnaryOp,
|
|
209
|
+
operand: Box<Expr>,
|
|
210
|
+
span: Span,
|
|
211
|
+
},
|
|
212
|
+
Call {
|
|
213
|
+
callee: Box<Expr>,
|
|
214
|
+
args: Vec<CallArg>,
|
|
215
|
+
span: Span,
|
|
216
|
+
},
|
|
217
|
+
Member {
|
|
218
|
+
object: Box<Expr>,
|
|
219
|
+
prop: MemberProp,
|
|
220
|
+
optional: bool,
|
|
221
|
+
span: Span,
|
|
222
|
+
},
|
|
223
|
+
Index {
|
|
224
|
+
object: Box<Expr>,
|
|
225
|
+
index: Box<Expr>,
|
|
226
|
+
optional: bool,
|
|
227
|
+
span: Span,
|
|
228
|
+
},
|
|
229
|
+
Conditional {
|
|
230
|
+
cond: Box<Expr>,
|
|
231
|
+
then_branch: Box<Expr>,
|
|
232
|
+
else_branch: Box<Expr>,
|
|
233
|
+
span: Span,
|
|
234
|
+
},
|
|
235
|
+
NullishCoalesce {
|
|
236
|
+
left: Box<Expr>,
|
|
237
|
+
right: Box<Expr>,
|
|
238
|
+
span: Span,
|
|
239
|
+
},
|
|
240
|
+
Array {
|
|
241
|
+
elements: Vec<ArrayElement>,
|
|
242
|
+
span: Span,
|
|
243
|
+
},
|
|
244
|
+
Object {
|
|
245
|
+
props: Vec<ObjectProp>,
|
|
246
|
+
span: Span,
|
|
247
|
+
},
|
|
248
|
+
Assign {
|
|
249
|
+
name: Arc<str>,
|
|
250
|
+
value: Box<Expr>,
|
|
251
|
+
span: Span,
|
|
252
|
+
},
|
|
253
|
+
TypeOf {
|
|
254
|
+
operand: Box<Expr>,
|
|
255
|
+
span: Span,
|
|
256
|
+
},
|
|
257
|
+
PostfixInc {
|
|
258
|
+
name: Arc<str>,
|
|
259
|
+
span: Span,
|
|
260
|
+
},
|
|
261
|
+
PostfixDec {
|
|
262
|
+
name: Arc<str>,
|
|
263
|
+
span: Span,
|
|
264
|
+
},
|
|
265
|
+
PrefixInc {
|
|
266
|
+
name: Arc<str>,
|
|
267
|
+
span: Span,
|
|
268
|
+
},
|
|
269
|
+
PrefixDec {
|
|
270
|
+
name: Arc<str>,
|
|
271
|
+
span: Span,
|
|
272
|
+
},
|
|
273
|
+
CompoundAssign {
|
|
274
|
+
name: Arc<str>,
|
|
275
|
+
op: CompoundOp,
|
|
276
|
+
value: Box<Expr>,
|
|
277
|
+
span: Span,
|
|
278
|
+
},
|
|
279
|
+
LogicalAssign {
|
|
280
|
+
name: Arc<str>,
|
|
281
|
+
op: LogicalAssignOp,
|
|
282
|
+
value: Box<Expr>,
|
|
283
|
+
span: Span,
|
|
284
|
+
},
|
|
285
|
+
/// Property assignment: obj.prop = value
|
|
286
|
+
MemberAssign {
|
|
287
|
+
object: Box<Expr>,
|
|
288
|
+
prop: Arc<str>,
|
|
289
|
+
value: Box<Expr>,
|
|
290
|
+
span: Span,
|
|
291
|
+
},
|
|
292
|
+
/// Index assignment: arr[index] = value
|
|
293
|
+
IndexAssign {
|
|
294
|
+
object: Box<Expr>,
|
|
295
|
+
index: Box<Expr>,
|
|
296
|
+
value: Box<Expr>,
|
|
297
|
+
span: Span,
|
|
298
|
+
},
|
|
299
|
+
/// Arrow function: (params) => body
|
|
300
|
+
ArrowFunction {
|
|
301
|
+
params: Vec<TypedParam>,
|
|
302
|
+
body: ArrowBody,
|
|
303
|
+
span: Span,
|
|
304
|
+
},
|
|
305
|
+
/// Template literal: `text ${expr} text`
|
|
306
|
+
TemplateLiteral {
|
|
307
|
+
quasis: Vec<Arc<str>>, // Static string parts (n+1 for n expressions)
|
|
308
|
+
exprs: Vec<Expr>, // Interpolated expressions (n)
|
|
309
|
+
span: Span,
|
|
310
|
+
},
|
|
311
|
+
/// Await expression: await operand
|
|
312
|
+
Await {
|
|
313
|
+
operand: Box<Expr>,
|
|
314
|
+
span: Span,
|
|
315
|
+
},
|
|
316
|
+
/// JSX element: <Tag props>children</Tag>
|
|
317
|
+
JsxElement {
|
|
318
|
+
tag: Arc<str>,
|
|
319
|
+
props: Vec<JsxProp>,
|
|
320
|
+
children: Vec<JsxChild>,
|
|
321
|
+
span: Span,
|
|
322
|
+
},
|
|
323
|
+
/// JSX fragment: <>children</>
|
|
324
|
+
JsxFragment {
|
|
325
|
+
children: Vec<JsxChild>,
|
|
326
|
+
span: Span,
|
|
327
|
+
},
|
|
328
|
+
/// Native module load: import { x } from 'tish:egui' → loads from tish_runtime
|
|
329
|
+
NativeModuleLoad {
|
|
330
|
+
spec: Arc<str>,
|
|
331
|
+
export_name: Arc<str>,
|
|
332
|
+
span: Span,
|
|
333
|
+
},
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/// JSX attribute/prop
|
|
337
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
338
|
+
pub enum JsxProp {
|
|
339
|
+
/// name="value" or name={expr} or name (boolean shorthand)
|
|
340
|
+
Attr {
|
|
341
|
+
name: Arc<str>,
|
|
342
|
+
value: JsxAttrValue,
|
|
343
|
+
},
|
|
344
|
+
/// {...expr}
|
|
345
|
+
Spread(Expr),
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/// JSX attribute value
|
|
349
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
350
|
+
pub enum JsxAttrValue {
|
|
351
|
+
/// "literal string"
|
|
352
|
+
String(Arc<str>),
|
|
353
|
+
/// {expr}
|
|
354
|
+
Expr(Expr),
|
|
355
|
+
/// name without value (e.g. disabled) = true
|
|
356
|
+
ImplicitTrue,
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/// JSX child node
|
|
360
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
361
|
+
pub enum JsxChild {
|
|
362
|
+
/// Text content
|
|
363
|
+
Text(Arc<str>),
|
|
364
|
+
/// {expr} or nested element
|
|
365
|
+
Expr(Expr),
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
impl Expr {
|
|
369
|
+
/// Return the source span for this expression.
|
|
370
|
+
pub fn span(&self) -> Span {
|
|
371
|
+
match self {
|
|
372
|
+
Expr::Literal { span, .. } => *span,
|
|
373
|
+
Expr::Ident { span, .. } => *span,
|
|
374
|
+
Expr::Binary { span, .. } => *span,
|
|
375
|
+
Expr::Unary { span, .. } => *span,
|
|
376
|
+
Expr::Call { span, .. } => *span,
|
|
377
|
+
Expr::Member { span, .. } => *span,
|
|
378
|
+
Expr::Index { span, .. } => *span,
|
|
379
|
+
Expr::Conditional { span, .. } => *span,
|
|
380
|
+
Expr::NullishCoalesce { span, .. } => *span,
|
|
381
|
+
Expr::Array { span, .. } => *span,
|
|
382
|
+
Expr::Object { span, .. } => *span,
|
|
383
|
+
Expr::Assign { span, .. } => *span,
|
|
384
|
+
Expr::TypeOf { span, .. } => *span,
|
|
385
|
+
Expr::PostfixInc { span, .. } => *span,
|
|
386
|
+
Expr::PostfixDec { span, .. } => *span,
|
|
387
|
+
Expr::PrefixInc { span, .. } => *span,
|
|
388
|
+
Expr::PrefixDec { span, .. } => *span,
|
|
389
|
+
Expr::CompoundAssign { span, .. } => *span,
|
|
390
|
+
Expr::LogicalAssign { span, .. } => *span,
|
|
391
|
+
Expr::MemberAssign { span, .. } => *span,
|
|
392
|
+
Expr::IndexAssign { span, .. } => *span,
|
|
393
|
+
Expr::ArrowFunction { span, .. } => *span,
|
|
394
|
+
Expr::TemplateLiteral { span, .. } => *span,
|
|
395
|
+
Expr::Await { span, .. } => *span,
|
|
396
|
+
Expr::JsxElement { span, .. } => *span,
|
|
397
|
+
Expr::JsxFragment { span, .. } => *span,
|
|
398
|
+
Expr::NativeModuleLoad { span, .. } => *span,
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/// Body of an arrow function: either an expression or a block
|
|
404
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
405
|
+
pub enum ArrowBody {
|
|
406
|
+
Expr(Box<Expr>),
|
|
407
|
+
Block(Box<Statement>),
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/// Array element: either a regular expression or spread element
|
|
411
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
412
|
+
pub enum ArrayElement {
|
|
413
|
+
Expr(Expr),
|
|
414
|
+
Spread(Expr),
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/// Object property: either a regular key-value pair or spread
|
|
418
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
419
|
+
pub enum ObjectProp {
|
|
420
|
+
KeyValue(Arc<str>, Expr),
|
|
421
|
+
Spread(Expr),
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/// Function call argument: either a regular argument or spread
|
|
425
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
426
|
+
pub enum CallArg {
|
|
427
|
+
Expr(Expr),
|
|
428
|
+
Spread(Expr),
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
432
|
+
pub enum CompoundOp {
|
|
433
|
+
Add, // +=
|
|
434
|
+
Sub, // -=
|
|
435
|
+
Mul, // *=
|
|
436
|
+
Div, // /=
|
|
437
|
+
Mod, // %=
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
441
|
+
pub enum LogicalAssignOp {
|
|
442
|
+
AndAnd, // &&=
|
|
443
|
+
OrOr, // ||=
|
|
444
|
+
Nullish, // ??=
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
448
|
+
pub enum Literal {
|
|
449
|
+
Number(f64),
|
|
450
|
+
String(Arc<str>),
|
|
451
|
+
Bool(bool),
|
|
452
|
+
Null,
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
456
|
+
pub enum BinOp {
|
|
457
|
+
Add,
|
|
458
|
+
Sub,
|
|
459
|
+
Mul,
|
|
460
|
+
Div,
|
|
461
|
+
Mod,
|
|
462
|
+
Pow,
|
|
463
|
+
Eq,
|
|
464
|
+
Ne,
|
|
465
|
+
StrictEq,
|
|
466
|
+
StrictNe,
|
|
467
|
+
Lt,
|
|
468
|
+
Le,
|
|
469
|
+
Gt,
|
|
470
|
+
Ge,
|
|
471
|
+
And,
|
|
472
|
+
Or,
|
|
473
|
+
BitAnd,
|
|
474
|
+
BitOr,
|
|
475
|
+
BitXor,
|
|
476
|
+
Shl,
|
|
477
|
+
Shr,
|
|
478
|
+
In,
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
482
|
+
pub enum UnaryOp {
|
|
483
|
+
Not,
|
|
484
|
+
Neg,
|
|
485
|
+
Pos,
|
|
486
|
+
BitNot,
|
|
487
|
+
Void,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
491
|
+
pub enum MemberProp {
|
|
492
|
+
Name(Arc<str>),
|
|
493
|
+
Expr(Box<Expr>), // for computed property
|
|
494
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
//! Shared build utilities for Tish.
|
|
2
|
+
//!
|
|
3
|
+
//! Provides workspace discovery, path resolution, and Cargo build orchestration
|
|
4
|
+
//! used by tish_wasm, tish_cranelift, tish_native, and the tish CLI.
|
|
5
|
+
|
|
6
|
+
use std::fs;
|
|
7
|
+
use std::path::{Path, PathBuf};
|
|
8
|
+
use std::process::Command;
|
|
9
|
+
|
|
10
|
+
/// Find the Tish workspace root using multiple strategies.
|
|
11
|
+
///
|
|
12
|
+
/// Returns the directory containing the workspace Cargo.toml (with [workspace]).
|
|
13
|
+
/// Used when building native binaries, WASM, or locating runtime crates.
|
|
14
|
+
pub fn find_workspace_root() -> Result<PathBuf, String> {
|
|
15
|
+
// Strategy 1: CARGO_MANIFEST_DIR (works during cargo build/run from workspace)
|
|
16
|
+
if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
|
|
17
|
+
let path = PathBuf::from(&manifest_dir);
|
|
18
|
+
// For crates/tish_*, workspace root is parent.parent()
|
|
19
|
+
if let Some(root) = path.parent().and_then(|p| p.parent()) {
|
|
20
|
+
let root_buf = root.to_path_buf();
|
|
21
|
+
if root_buf.join("Cargo.toml").exists() {
|
|
22
|
+
return Ok(root_buf);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Strategy 2: Walk from current executable (e.g. target/debug/tish)
|
|
28
|
+
if let Ok(exe) = std::env::current_exe() {
|
|
29
|
+
if let Some(mut current) = exe.parent() {
|
|
30
|
+
for _ in 0..15 {
|
|
31
|
+
let crates_dir = current.join("crates");
|
|
32
|
+
if crates_dir.join("tish_runtime").exists() || crates_dir.join("tish_cranelift_runtime").exists() {
|
|
33
|
+
return Ok(current.to_path_buf());
|
|
34
|
+
}
|
|
35
|
+
if let Some(p) = current.parent() {
|
|
36
|
+
current = p;
|
|
37
|
+
} else {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Strategy 3: Walk from current working directory
|
|
45
|
+
if let Ok(mut current) = std::env::current_dir() {
|
|
46
|
+
for _ in 0..15 {
|
|
47
|
+
let cargo_toml = current.join("Cargo.toml");
|
|
48
|
+
if cargo_toml.exists() {
|
|
49
|
+
if let Ok(content) = std::fs::read_to_string(&cargo_toml) {
|
|
50
|
+
if content.contains("[workspace]") {
|
|
51
|
+
return Ok(current);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Fallback: check for crates dir with known crates
|
|
55
|
+
let crates_dir = current.join("crates");
|
|
56
|
+
if crates_dir.join("tish_runtime").exists() {
|
|
57
|
+
return Ok(current);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if !current.pop() {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
Err("Cannot find Tish workspace root. Run from workspace root or use cargo run.".to_string())
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Find the path to the tish_runtime crate.
|
|
70
|
+
///
|
|
71
|
+
/// Returns a canonical path string suitable for Cargo.toml path dependencies.
|
|
72
|
+
pub fn find_runtime_path() -> Result<String, String> {
|
|
73
|
+
let workspace = find_workspace_root()?;
|
|
74
|
+
let runtime = workspace.join("crates").join("tish_runtime");
|
|
75
|
+
if !runtime.exists() {
|
|
76
|
+
return Err("tish_runtime crate not found".to_string());
|
|
77
|
+
}
|
|
78
|
+
runtime
|
|
79
|
+
.canonicalize()
|
|
80
|
+
.map_err(|e| format!("Cannot canonicalize tish_runtime: {}", e))
|
|
81
|
+
.map(|p| p.display().to_string().replace('\\', "/"))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// Find the path to a crate within the workspace by name.
|
|
85
|
+
///
|
|
86
|
+
/// e.g. `find_crate_path("tish_cranelift_runtime")` returns the path to crates/tish_cranelift_runtime.
|
|
87
|
+
pub fn find_crate_path(crate_name: &str) -> Result<PathBuf, String> {
|
|
88
|
+
let workspace = find_workspace_root()?;
|
|
89
|
+
let crate_path = workspace.join("crates").join(crate_name);
|
|
90
|
+
if !crate_path.exists() {
|
|
91
|
+
return Err(format!("Crate {} not found", crate_name));
|
|
92
|
+
}
|
|
93
|
+
Ok(crate_path)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// Create a temp build directory with src subdir.
|
|
97
|
+
pub fn create_build_dir(prefix: &str, out_name: &str) -> Result<PathBuf, String> {
|
|
98
|
+
let build_dir = std::env::temp_dir().join(prefix).join(format!("{}_{}", out_name, std::process::id()));
|
|
99
|
+
fs::create_dir_all(&build_dir).map_err(|e| format!("Cannot create build dir: {}", e))?;
|
|
100
|
+
fs::create_dir_all(build_dir.join("src")).map_err(|e| format!("Cannot create src dir: {}", e))?;
|
|
101
|
+
Ok(build_dir)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/// Run cargo build in the given directory.
|
|
105
|
+
/// If target_dir is Some, use that for --target-dir (e.g. workspace target for caching).
|
|
106
|
+
pub fn run_cargo_build(build_dir: &Path, target_dir: Option<&Path>) -> Result<(), String> {
|
|
107
|
+
let target_dir = target_dir.map(|p| p.to_path_buf()).unwrap_or_else(|| build_dir.join("target"));
|
|
108
|
+
let output = Command::new("cargo")
|
|
109
|
+
.args(["build", "--release", "--target-dir"])
|
|
110
|
+
.arg(&target_dir)
|
|
111
|
+
.current_dir(build_dir)
|
|
112
|
+
.env_remove("CARGO_TARGET_DIR")
|
|
113
|
+
.env("CARGO_TERM_PROGRESS", "always")
|
|
114
|
+
.output()
|
|
115
|
+
.map_err(|e| format!("Failed to run cargo: {}", e))?;
|
|
116
|
+
|
|
117
|
+
if !output.status.success() {
|
|
118
|
+
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
119
|
+
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
120
|
+
return Err(format!("Compilation failed.\nstdout:\n{}\nstderr:\n{}", stdout, stderr));
|
|
121
|
+
}
|
|
122
|
+
Ok(())
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Find the built binary in target/release.
|
|
126
|
+
pub fn find_release_binary(binary_dir: &Path, bin_name: &str) -> Result<PathBuf, String> {
|
|
127
|
+
let binary_no_ext = binary_dir.join(bin_name);
|
|
128
|
+
let binary_exe = binary_dir.join(format!("{}.exe", bin_name));
|
|
129
|
+
if binary_no_ext.exists() {
|
|
130
|
+
Ok(binary_no_ext)
|
|
131
|
+
} else if binary_exe.exists() {
|
|
132
|
+
Ok(binary_exe)
|
|
133
|
+
} else {
|
|
134
|
+
Err(format!(
|
|
135
|
+
"Binary not found at {} or {}",
|
|
136
|
+
binary_no_ext.display(),
|
|
137
|
+
binary_exe.display()
|
|
138
|
+
))
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// Resolve the output path for the binary (handles extension, directory).
|
|
143
|
+
pub fn resolve_output_path(output_path: &Path, bin_name: &str) -> PathBuf {
|
|
144
|
+
if output_path.extension().is_none()
|
|
145
|
+
|| output_path.extension() == Some(std::ffi::OsStr::new(""))
|
|
146
|
+
{
|
|
147
|
+
let mut p = output_path.to_path_buf();
|
|
148
|
+
if cfg!(windows) {
|
|
149
|
+
p.set_extension("exe");
|
|
150
|
+
}
|
|
151
|
+
return p;
|
|
152
|
+
}
|
|
153
|
+
if output_path.to_string_lossy().ends_with('/') || output_path.is_dir() {
|
|
154
|
+
let dir = if output_path.is_dir() {
|
|
155
|
+
output_path.to_path_buf()
|
|
156
|
+
} else {
|
|
157
|
+
output_path.parent().unwrap_or(Path::new(".")).to_path_buf()
|
|
158
|
+
};
|
|
159
|
+
return dir.join(if cfg!(windows) {
|
|
160
|
+
format!("{}.exe", bin_name)
|
|
161
|
+
} else {
|
|
162
|
+
bin_name.to_string()
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
output_path.to_path_buf()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/// Copy the built binary to the output path.
|
|
169
|
+
pub fn copy_binary_to_output(binary: &Path, output_path: &Path) -> Result<(), String> {
|
|
170
|
+
if let Some(parent) = output_path.parent() {
|
|
171
|
+
fs::create_dir_all(parent).map_err(|e| format!("Cannot create output dir: {}", e))?;
|
|
172
|
+
}
|
|
173
|
+
fs::copy(binary, output_path).map_err(|e| format!("Cannot copy to {}: {}", output_path.display(), e))?;
|
|
174
|
+
Ok(())
|
|
175
|
+
}
|