@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.
Files changed (127) hide show
  1. package/Cargo.toml +43 -0
  2. package/LICENSE +13 -0
  3. package/README.md +66 -0
  4. package/crates/js_to_tish/Cargo.toml +9 -0
  5. package/crates/js_to_tish/README.md +18 -0
  6. package/crates/js_to_tish/src/error.rs +61 -0
  7. package/crates/js_to_tish/src/lib.rs +11 -0
  8. package/crates/js_to_tish/src/span_util.rs +35 -0
  9. package/crates/js_to_tish/src/transform/expr.rs +608 -0
  10. package/crates/js_to_tish/src/transform/stmt.rs +474 -0
  11. package/crates/js_to_tish/src/transform.rs +60 -0
  12. package/crates/tish/Cargo.toml +44 -0
  13. package/crates/tish/src/main.rs +585 -0
  14. package/crates/tish/src/repl_completion.rs +200 -0
  15. package/crates/tish/tests/integration_test.rs +726 -0
  16. package/crates/tish_ast/Cargo.toml +7 -0
  17. package/crates/tish_ast/src/ast.rs +494 -0
  18. package/crates/tish_ast/src/lib.rs +5 -0
  19. package/crates/tish_build_utils/Cargo.toml +5 -0
  20. package/crates/tish_build_utils/src/lib.rs +175 -0
  21. package/crates/tish_builtins/Cargo.toml +12 -0
  22. package/crates/tish_builtins/src/array.rs +410 -0
  23. package/crates/tish_builtins/src/globals.rs +197 -0
  24. package/crates/tish_builtins/src/helpers.rs +38 -0
  25. package/crates/tish_builtins/src/lib.rs +14 -0
  26. package/crates/tish_builtins/src/math.rs +80 -0
  27. package/crates/tish_builtins/src/object.rs +36 -0
  28. package/crates/tish_builtins/src/string.rs +253 -0
  29. package/crates/tish_bytecode/Cargo.toml +15 -0
  30. package/crates/tish_bytecode/src/chunk.rs +97 -0
  31. package/crates/tish_bytecode/src/compiler.rs +1361 -0
  32. package/crates/tish_bytecode/src/encoding.rs +100 -0
  33. package/crates/tish_bytecode/src/lib.rs +19 -0
  34. package/crates/tish_bytecode/src/opcode.rs +110 -0
  35. package/crates/tish_bytecode/src/peephole.rs +159 -0
  36. package/crates/tish_bytecode/src/serialize.rs +163 -0
  37. package/crates/tish_bytecode/tests/constant_folding.rs +84 -0
  38. package/crates/tish_bytecode/tests/shortcircuit.rs +49 -0
  39. package/crates/tish_bytecode/tests/sort_optimization.rs +31 -0
  40. package/crates/tish_compile/Cargo.toml +21 -0
  41. package/crates/tish_compile/src/codegen.rs +3316 -0
  42. package/crates/tish_compile/src/lib.rs +71 -0
  43. package/crates/tish_compile/src/resolve.rs +631 -0
  44. package/crates/tish_compile/src/types.rs +304 -0
  45. package/crates/tish_compile_js/Cargo.toml +16 -0
  46. package/crates/tish_compile_js/examples/jsx_vdom_smoke.tish +8 -0
  47. package/crates/tish_compile_js/src/codegen.rs +794 -0
  48. package/crates/tish_compile_js/src/error.rs +20 -0
  49. package/crates/tish_compile_js/src/js_intrinsics.rs +82 -0
  50. package/crates/tish_compile_js/src/lib.rs +27 -0
  51. package/crates/tish_compile_js/src/tests_jsx.rs +32 -0
  52. package/crates/tish_compiler_wasm/Cargo.toml +19 -0
  53. package/crates/tish_compiler_wasm/src/lib.rs +55 -0
  54. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +462 -0
  55. package/crates/tish_core/Cargo.toml +11 -0
  56. package/crates/tish_core/src/console_style.rs +128 -0
  57. package/crates/tish_core/src/json.rs +327 -0
  58. package/crates/tish_core/src/lib.rs +15 -0
  59. package/crates/tish_core/src/macros.rs +37 -0
  60. package/crates/tish_core/src/uri.rs +115 -0
  61. package/crates/tish_core/src/value.rs +376 -0
  62. package/crates/tish_cranelift/Cargo.toml +17 -0
  63. package/crates/tish_cranelift/src/lib.rs +41 -0
  64. package/crates/tish_cranelift/src/link.rs +120 -0
  65. package/crates/tish_cranelift/src/lower.rs +77 -0
  66. package/crates/tish_cranelift_runtime/Cargo.toml +19 -0
  67. package/crates/tish_cranelift_runtime/src/lib.rs +43 -0
  68. package/crates/tish_eval/Cargo.toml +26 -0
  69. package/crates/tish_eval/src/eval.rs +3205 -0
  70. package/crates/tish_eval/src/http.rs +122 -0
  71. package/crates/tish_eval/src/lib.rs +59 -0
  72. package/crates/tish_eval/src/natives.rs +301 -0
  73. package/crates/tish_eval/src/promise.rs +173 -0
  74. package/crates/tish_eval/src/regex.rs +298 -0
  75. package/crates/tish_eval/src/timers.rs +111 -0
  76. package/crates/tish_eval/src/value.rs +224 -0
  77. package/crates/tish_eval/src/value_convert.rs +85 -0
  78. package/crates/tish_fmt/Cargo.toml +16 -0
  79. package/crates/tish_fmt/src/bin/tish-fmt.rs +41 -0
  80. package/crates/tish_fmt/src/lib.rs +884 -0
  81. package/crates/tish_jsx_web/Cargo.toml +7 -0
  82. package/crates/tish_jsx_web/README.md +18 -0
  83. package/crates/tish_jsx_web/src/lib.rs +157 -0
  84. package/crates/tish_jsx_web/vendor/Lattish.tish +347 -0
  85. package/crates/tish_lexer/Cargo.toml +7 -0
  86. package/crates/tish_lexer/src/lib.rs +430 -0
  87. package/crates/tish_lexer/src/token.rs +155 -0
  88. package/crates/tish_lint/Cargo.toml +17 -0
  89. package/crates/tish_lint/src/bin/tish-lint.rs +77 -0
  90. package/crates/tish_lint/src/lib.rs +278 -0
  91. package/crates/tish_llvm/Cargo.toml +11 -0
  92. package/crates/tish_llvm/src/lib.rs +106 -0
  93. package/crates/tish_lsp/Cargo.toml +22 -0
  94. package/crates/tish_lsp/README.md +26 -0
  95. package/crates/tish_lsp/src/main.rs +615 -0
  96. package/crates/tish_native/Cargo.toml +14 -0
  97. package/crates/tish_native/src/build.rs +102 -0
  98. package/crates/tish_native/src/lib.rs +237 -0
  99. package/crates/tish_opt/Cargo.toml +11 -0
  100. package/crates/tish_opt/src/lib.rs +896 -0
  101. package/crates/tish_parser/Cargo.toml +9 -0
  102. package/crates/tish_parser/src/lib.rs +123 -0
  103. package/crates/tish_parser/src/parser.rs +1714 -0
  104. package/crates/tish_runtime/Cargo.toml +26 -0
  105. package/crates/tish_runtime/src/http.rs +308 -0
  106. package/crates/tish_runtime/src/http_fetch.rs +453 -0
  107. package/crates/tish_runtime/src/lib.rs +1004 -0
  108. package/crates/tish_runtime/src/native_promise.rs +26 -0
  109. package/crates/tish_runtime/src/promise.rs +77 -0
  110. package/crates/tish_runtime/src/promise_io.rs +41 -0
  111. package/crates/tish_runtime/src/timers.rs +125 -0
  112. package/crates/tish_runtime/src/ws.rs +725 -0
  113. package/crates/tish_runtime/tests/fetch_readable_stream.rs +99 -0
  114. package/crates/tish_vm/Cargo.toml +31 -0
  115. package/crates/tish_vm/src/lib.rs +39 -0
  116. package/crates/tish_vm/src/vm.rs +1399 -0
  117. package/crates/tish_wasm/Cargo.toml +13 -0
  118. package/crates/tish_wasm/src/lib.rs +358 -0
  119. package/crates/tish_wasm_runtime/Cargo.toml +25 -0
  120. package/crates/tish_wasm_runtime/src/lib.rs +36 -0
  121. package/justfile +260 -0
  122. package/package.json +8 -3
  123. package/platform/darwin-arm64/tish +0 -0
  124. package/platform/darwin-x64/tish +0 -0
  125. package/platform/linux-arm64/tish +0 -0
  126. package/platform/linux-x64/tish +0 -0
  127. package/platform/win32-x64/tish.exe +0 -0
@@ -0,0 +1,7 @@
1
+ [package]
2
+ name = "tish_ast"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Tish AST types and span info"
6
+
7
+ [dependencies]
@@ -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,5 @@
1
+ //! Tish AST types and span info.
2
+
3
+ mod ast;
4
+
5
+ pub use ast::*;
@@ -0,0 +1,5 @@
1
+ [package]
2
+ name = "tish_build_utils"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Shared build utilities for Tish (workspace discovery, path resolution)"
@@ -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
+ }
@@ -0,0 +1,12 @@
1
+ [package]
2
+ name = "tish_builtins"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+
6
+ [dependencies]
7
+ rand = "0.10.0"
8
+ tish_core = { path = "../tish_core" }
9
+
10
+ [features]
11
+ default = []
12
+ regex = ["tish_core/regex"]