@tishlang/tish 1.7.0 → 1.8.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 (95) hide show
  1. package/Cargo.toml +1 -0
  2. package/README.md +2 -0
  3. package/bin/tish +0 -0
  4. package/crates/js_to_tish/src/transform/expr.rs +28 -8
  5. package/crates/js_to_tish/src/transform/stmt.rs +49 -22
  6. package/crates/tish/Cargo.toml +15 -5
  7. package/crates/tish/src/cargo_native_registry.rs +29 -0
  8. package/crates/tish/src/cli_help.rs +16 -10
  9. package/crates/tish/src/main.rs +87 -32
  10. package/crates/tish/src/repl_completion.rs +3 -3
  11. package/crates/tish/tests/cargo_example_compile.rs +1 -1
  12. package/crates/tish/tests/integration_test.rs +19 -7
  13. package/crates/tish/tests/shortcircuit.rs +1 -1
  14. package/crates/tish_ast/src/ast.rs +80 -9
  15. package/crates/tish_build_utils/Cargo.toml +4 -0
  16. package/crates/tish_build_utils/src/lib.rs +105 -2
  17. package/crates/tish_builtins/Cargo.toml +5 -1
  18. package/crates/tish_builtins/src/array.rs +13 -12
  19. package/crates/tish_builtins/src/construct.rs +34 -33
  20. package/crates/tish_builtins/src/globals.rs +12 -11
  21. package/crates/tish_builtins/src/helpers.rs +2 -1
  22. package/crates/tish_builtins/src/object.rs +3 -2
  23. package/crates/tish_builtins/src/string.rs +73 -3
  24. package/crates/tish_bytecode/src/compiler.rs +12 -14
  25. package/crates/tish_bytecode/src/opcode.rs +12 -3
  26. package/crates/tish_compile/Cargo.toml +1 -0
  27. package/crates/tish_compile/src/codegen.rs +745 -199
  28. package/crates/tish_compile/src/infer.rs +6 -0
  29. package/crates/tish_compile/src/lib.rs +4 -3
  30. package/crates/tish_compile/src/resolve.rs +180 -82
  31. package/crates/tish_compile/src/types.rs +175 -11
  32. package/crates/tish_compile_js/Cargo.toml +1 -0
  33. package/crates/tish_compile_js/src/codegen.rs +152 -29
  34. package/crates/tish_compile_js/src/lib.rs +3 -1
  35. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +31 -12
  36. package/crates/tish_core/Cargo.toml +8 -0
  37. package/crates/tish_core/src/json.rs +102 -53
  38. package/crates/tish_core/src/lib.rs +3 -1
  39. package/crates/tish_core/src/macros.rs +5 -5
  40. package/crates/tish_core/src/value.rs +53 -15
  41. package/crates/tish_core/src/vmref.rs +178 -0
  42. package/crates/tish_eval/Cargo.toml +17 -2
  43. package/crates/tish_eval/src/eval.rs +90 -28
  44. package/crates/tish_eval/src/http.rs +61 -0
  45. package/crates/tish_eval/src/lib.rs +3 -3
  46. package/crates/tish_eval/src/natives.rs +41 -0
  47. package/crates/tish_eval/src/value.rs +7 -3
  48. package/crates/tish_eval/src/value_convert.rs +13 -5
  49. package/crates/tish_fmt/src/lib.rs +120 -30
  50. package/crates/tish_lexer/src/lib.rs +20 -5
  51. package/crates/tish_lexer/src/token.rs +4 -0
  52. package/crates/tish_llvm/src/lib.rs +3 -1
  53. package/crates/tish_lsp/Cargo.toml +4 -1
  54. package/crates/tish_lsp/README.md +1 -1
  55. package/crates/tish_lsp/src/builtin_goto.rs +261 -0
  56. package/crates/tish_lsp/src/import_goto.rs +549 -0
  57. package/crates/tish_lsp/src/main.rs +502 -102
  58. package/crates/tish_native/src/build.rs +3 -2
  59. package/crates/tish_native/src/lib.rs +6 -2
  60. package/crates/tish_opt/src/lib.rs +17 -2
  61. package/crates/tish_parser/src/lib.rs +10 -3
  62. package/crates/tish_parser/src/parser.rs +346 -56
  63. package/crates/tish_resolve/Cargo.toml +13 -0
  64. package/crates/tish_resolve/src/lib.rs +3436 -0
  65. package/crates/tish_resolve/src/pos.rs +133 -0
  66. package/crates/tish_runtime/Cargo.toml +68 -3
  67. package/crates/tish_runtime/src/http.rs +1123 -141
  68. package/crates/tish_runtime/src/http_fetch.rs +15 -14
  69. package/crates/tish_runtime/src/http_hyper.rs +418 -0
  70. package/crates/tish_runtime/src/http_prefork.rs +189 -0
  71. package/crates/tish_runtime/src/lib.rs +159 -29
  72. package/crates/tish_runtime/src/promise.rs +199 -36
  73. package/crates/tish_runtime/src/promise_io.rs +2 -1
  74. package/crates/tish_runtime/src/timers.rs +37 -1
  75. package/crates/tish_runtime/src/ws.rs +26 -28
  76. package/crates/tish_ui/src/jsx.rs +279 -8
  77. package/crates/tish_ui/src/lib.rs +5 -2
  78. package/crates/tish_ui/src/runtime/hooks.rs +406 -45
  79. package/crates/tish_ui/src/runtime/mod.rs +36 -9
  80. package/crates/tish_vm/Cargo.toml +15 -5
  81. package/crates/tish_vm/src/vm.rs +506 -259
  82. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +3 -1
  83. package/crates/tish_wasm/src/lib.rs +17 -14
  84. package/crates/tish_wasm_runtime/Cargo.toml +2 -1
  85. package/crates/tish_wasm_runtime/src/lib.rs +1 -1
  86. package/crates/tishlang_cargo_bindgen/Cargo.toml +1 -0
  87. package/crates/tishlang_cargo_bindgen/src/discover.rs +68 -0
  88. package/crates/tishlang_cargo_bindgen/src/lib.rs +5 -4
  89. package/justfile +8 -0
  90. package/package.json +1 -1
  91. package/platform/darwin-arm64/tish +0 -0
  92. package/platform/darwin-x64/tish +0 -0
  93. package/platform/linux-arm64/tish +0 -0
  94. package/platform/linux-x64/tish +0 -0
  95. package/platform/win32-x64/tish.exe +0 -0
@@ -1,6 +1,11 @@
1
1
  //! Shared JSX lowering: emit `h(tag, props, children)` as JavaScript or Rust (`Value`) source.
2
2
 
3
- use tishlang_ast::{ArrayElement, Expr, JsxAttrValue, JsxChild, JsxProp, Literal, ObjectProp};
3
+ use std::collections::HashSet;
4
+
5
+ use tishlang_ast::{
6
+ ArrayElement, ArrowBody, CallArg, ExportDeclaration, Expr, JsxAttrValue, JsxChild, JsxProp,
7
+ Literal, MemberProp, ObjectProp, Program, Statement,
8
+ };
4
9
 
5
10
  /// Escape a Tish identifier for Rust output (matches `tishlang_compile` conventions).
6
11
  pub fn escape_ident_rust(s: &str) -> String {
@@ -114,8 +119,265 @@ where
114
119
  }
115
120
  }
116
121
 
122
+ /// Every `fn Foo` name in the program (including nested bodies), for Rust JSX tag lowering.
123
+ ///
124
+ /// PascalCase JSX tags that match a name here are emitted as a Rust identifier (component
125
+ /// `Value::Function`). Other PascalCase tags become `Value::String("Tag")` (native intrinsics).
126
+ pub fn collect_fun_decl_names(program: &Program) -> HashSet<String> {
127
+ let mut names = HashSet::new();
128
+ for s in &program.statements {
129
+ collect_fun_decl_names_stmt(s, &mut names);
130
+ }
131
+ names
132
+ }
133
+
134
+ fn collect_fun_decl_names_stmt(stmt: &Statement, names: &mut HashSet<String>) {
135
+ match stmt {
136
+ Statement::FunDecl { name, body, .. } => {
137
+ names.insert(name.to_string());
138
+ collect_fun_decl_names_stmt(body, names);
139
+ }
140
+ Statement::Block { statements, .. } => {
141
+ for s in statements {
142
+ collect_fun_decl_names_stmt(s, names);
143
+ }
144
+ }
145
+ Statement::VarDecl { init, .. } => {
146
+ if let Some(e) = init {
147
+ collect_fun_decl_names_expr(e, names);
148
+ }
149
+ }
150
+ Statement::VarDeclDestructure { init, .. } => collect_fun_decl_names_expr(init, names),
151
+ Statement::ExprStmt { expr, .. } => collect_fun_decl_names_expr(expr, names),
152
+ Statement::If {
153
+ cond,
154
+ then_branch,
155
+ else_branch,
156
+ ..
157
+ } => {
158
+ collect_fun_decl_names_expr(cond, names);
159
+ collect_fun_decl_names_stmt(then_branch, names);
160
+ if let Some(e) = else_branch {
161
+ collect_fun_decl_names_stmt(e, names);
162
+ }
163
+ }
164
+ Statement::While { cond, body, .. } => {
165
+ collect_fun_decl_names_expr(cond, names);
166
+ collect_fun_decl_names_stmt(body, names);
167
+ }
168
+ Statement::For {
169
+ init,
170
+ cond,
171
+ update,
172
+ body,
173
+ ..
174
+ } => {
175
+ if let Some(i) = init {
176
+ collect_fun_decl_names_stmt(i, names);
177
+ }
178
+ if let Some(c) = cond {
179
+ collect_fun_decl_names_expr(c, names);
180
+ }
181
+ if let Some(u) = update {
182
+ collect_fun_decl_names_expr(u, names);
183
+ }
184
+ collect_fun_decl_names_stmt(body, names);
185
+ }
186
+ Statement::ForOf { iterable, body, .. } => {
187
+ collect_fun_decl_names_expr(iterable, names);
188
+ collect_fun_decl_names_stmt(body, names);
189
+ }
190
+ Statement::Return { value, .. } => {
191
+ if let Some(e) = value {
192
+ collect_fun_decl_names_expr(e, names);
193
+ }
194
+ }
195
+ Statement::Switch {
196
+ expr,
197
+ cases,
198
+ default_body,
199
+ ..
200
+ } => {
201
+ collect_fun_decl_names_expr(expr, names);
202
+ for (ce, ss) in cases {
203
+ if let Some(e) = ce {
204
+ collect_fun_decl_names_expr(e, names);
205
+ }
206
+ for s in ss {
207
+ collect_fun_decl_names_stmt(s, names);
208
+ }
209
+ }
210
+ if let Some(ss) = default_body {
211
+ for s in ss {
212
+ collect_fun_decl_names_stmt(s, names);
213
+ }
214
+ }
215
+ }
216
+ Statement::DoWhile { body, cond, .. } => {
217
+ collect_fun_decl_names_stmt(body, names);
218
+ collect_fun_decl_names_expr(cond, names);
219
+ }
220
+ Statement::Throw { value, .. } => collect_fun_decl_names_expr(value, names),
221
+ Statement::Try {
222
+ body,
223
+ catch_body,
224
+ finally_body,
225
+ ..
226
+ } => {
227
+ collect_fun_decl_names_stmt(body, names);
228
+ if let Some(c) = catch_body {
229
+ collect_fun_decl_names_stmt(c, names);
230
+ }
231
+ if let Some(f) = finally_body {
232
+ collect_fun_decl_names_stmt(f, names);
233
+ }
234
+ }
235
+ Statement::Export { declaration, .. } => match declaration.as_ref() {
236
+ ExportDeclaration::Named(inner) => collect_fun_decl_names_stmt(inner, names),
237
+ ExportDeclaration::Default(e) => collect_fun_decl_names_expr(e, names),
238
+ },
239
+ Statement::Import { .. }
240
+ | Statement::Break { .. }
241
+ | Statement::Continue { .. }
242
+ | Statement::TypeAlias { .. }
243
+ | Statement::DeclareVar { .. }
244
+ | Statement::DeclareFun { .. } => {}
245
+ }
246
+ }
247
+
248
+ fn collect_fun_decl_names_expr(expr: &Expr, names: &mut HashSet<String>) {
249
+ match expr {
250
+ Expr::ArrowFunction { body, .. } => match body {
251
+ ArrowBody::Expr(e) => collect_fun_decl_names_expr(e, names),
252
+ ArrowBody::Block(s) => collect_fun_decl_names_stmt(s, names),
253
+ },
254
+ Expr::Binary { left, right, .. } => {
255
+ collect_fun_decl_names_expr(left, names);
256
+ collect_fun_decl_names_expr(right, names);
257
+ }
258
+ Expr::Unary { operand, .. } => collect_fun_decl_names_expr(operand, names),
259
+ Expr::Assign { value, .. } => collect_fun_decl_names_expr(value, names),
260
+ Expr::Call { callee, args, .. } => {
261
+ collect_fun_decl_names_expr(callee, names);
262
+ for a in args {
263
+ match a {
264
+ CallArg::Expr(e) | CallArg::Spread(e) => collect_fun_decl_names_expr(e, names),
265
+ }
266
+ }
267
+ }
268
+ Expr::Member { object, prop, .. } => {
269
+ collect_fun_decl_names_expr(object, names);
270
+ if let MemberProp::Expr(e) = prop {
271
+ collect_fun_decl_names_expr(e, names);
272
+ }
273
+ }
274
+ Expr::Index { object, index, .. } => {
275
+ collect_fun_decl_names_expr(object, names);
276
+ collect_fun_decl_names_expr(index, names);
277
+ }
278
+ Expr::Conditional {
279
+ cond,
280
+ then_branch,
281
+ else_branch,
282
+ ..
283
+ } => {
284
+ collect_fun_decl_names_expr(cond, names);
285
+ collect_fun_decl_names_expr(then_branch, names);
286
+ collect_fun_decl_names_expr(else_branch, names);
287
+ }
288
+ Expr::Array { elements, .. } => {
289
+ for el in elements {
290
+ match el {
291
+ ArrayElement::Expr(e) | ArrayElement::Spread(e) => {
292
+ collect_fun_decl_names_expr(e, names);
293
+ }
294
+ }
295
+ }
296
+ }
297
+ Expr::Object { props, .. } => {
298
+ for p in props {
299
+ match p {
300
+ ObjectProp::KeyValue(_, e) | ObjectProp::Spread(e) => {
301
+ collect_fun_decl_names_expr(e, names);
302
+ }
303
+ }
304
+ }
305
+ }
306
+ Expr::NullishCoalesce { left, right, .. } => {
307
+ collect_fun_decl_names_expr(left, names);
308
+ collect_fun_decl_names_expr(right, names);
309
+ }
310
+ Expr::TemplateLiteral { exprs, .. } => {
311
+ for e in exprs {
312
+ collect_fun_decl_names_expr(e, names);
313
+ }
314
+ }
315
+ Expr::Await { operand, .. } | Expr::TypeOf { operand, .. } => {
316
+ collect_fun_decl_names_expr(operand, names);
317
+ }
318
+ Expr::CompoundAssign { value, .. } | Expr::LogicalAssign { value, .. } => {
319
+ collect_fun_decl_names_expr(value, names);
320
+ }
321
+ Expr::MemberAssign { object, value, .. } => {
322
+ collect_fun_decl_names_expr(object, names);
323
+ collect_fun_decl_names_expr(value, names);
324
+ }
325
+ Expr::IndexAssign {
326
+ object,
327
+ index,
328
+ value,
329
+ ..
330
+ } => {
331
+ collect_fun_decl_names_expr(object, names);
332
+ collect_fun_decl_names_expr(index, names);
333
+ collect_fun_decl_names_expr(value, names);
334
+ }
335
+ Expr::New { callee, args, .. } => {
336
+ collect_fun_decl_names_expr(callee, names);
337
+ for a in args {
338
+ match a {
339
+ CallArg::Expr(e) | CallArg::Spread(e) => collect_fun_decl_names_expr(e, names),
340
+ }
341
+ }
342
+ }
343
+ Expr::PostfixInc { .. }
344
+ | Expr::PrefixInc { .. }
345
+ | Expr::PostfixDec { .. }
346
+ | Expr::PrefixDec { .. } => {}
347
+ Expr::JsxElement { props, children, .. } => {
348
+ for p in props {
349
+ match p {
350
+ JsxProp::Attr { value, .. } => {
351
+ if let JsxAttrValue::Expr(e) = value {
352
+ collect_fun_decl_names_expr(e, names);
353
+ }
354
+ }
355
+ JsxProp::Spread(e) => collect_fun_decl_names_expr(e, names),
356
+ }
357
+ }
358
+ for c in children {
359
+ if let JsxChild::Expr(e) = c {
360
+ collect_fun_decl_names_expr(e, names);
361
+ }
362
+ }
363
+ }
364
+ Expr::JsxFragment { children, .. } => {
365
+ for c in children {
366
+ if let JsxChild::Expr(e) = c {
367
+ collect_fun_decl_names_expr(e, names);
368
+ }
369
+ }
370
+ }
371
+ Expr::Literal { .. } | Expr::Ident { .. } | Expr::NativeModuleLoad { .. } => {}
372
+ }
373
+ }
374
+
117
375
  /// Emit JSX as Rust `Value` by calling `tishlang_ui::ui_h` directly (no closure capture of a local `h` binding).
118
- pub fn emit_jsx_rust<F, E>(expr: &Expr, emit_expr: &mut F) -> Result<String, E>
376
+ pub fn emit_jsx_rust<F, E>(
377
+ expr: &Expr,
378
+ emit_expr: &mut F,
379
+ fun_decls: &HashSet<String>,
380
+ ) -> Result<String, E>
119
381
  where
120
382
  F: FnMut(&Expr) -> Result<String, E>,
121
383
  E: From<String>,
@@ -133,7 +395,11 @@ where
133
395
  .map(|c| c.is_uppercase())
134
396
  .unwrap_or(false);
135
397
  let tag_rust = if is_component {
136
- escape_ident_rust(tag.as_ref())
398
+ if fun_decls.contains(tag.as_ref()) {
399
+ escape_ident_rust(tag.as_ref())
400
+ } else {
401
+ format!("Value::String({:?}.into())", tag.as_ref())
402
+ }
137
403
  } else {
138
404
  format!("Value::String({:?}.into())", tag.as_ref())
139
405
  };
@@ -143,7 +409,7 @@ where
143
409
  .map(|c| emit_jsx_child_rust(c, emit_expr))
144
410
  .collect();
145
411
  let children_rust = format!(
146
- "Value::Array(Rc::new(RefCell::new(vec![{}])))",
412
+ "Value::Array(VmRef::new(vec![{}]))",
147
413
  child_parts?.join(", ")
148
414
  );
149
415
  Ok(wrap_h_call_rust(&tag_rust, &props_rust, &children_rust))
@@ -154,7 +420,7 @@ where
154
420
  .map(|c| emit_jsx_child_rust(c, emit_expr))
155
421
  .collect();
156
422
  let children_rust = format!(
157
- "Value::Array(Rc::new(RefCell::new(vec![{}])))",
423
+ "Value::Array(VmRef::new(vec![{}]))",
158
424
  child_parts?.join(", ")
159
425
  );
160
426
  Ok(wrap_h_call_rust("Fragment", "Value::Null", &children_rust))
@@ -207,7 +473,7 @@ where
207
473
  }
208
474
  }
209
475
  Ok(format!(
210
- "{{ let mut _obj: ObjectMap = ObjectMap::default(); {} Value::Object(Rc::new(RefCell::new(_obj))) }}",
476
+ "{{ let mut _obj: ObjectMap = ObjectMap::default(); {} Value::Object(VmRef::new(_obj)) }}",
211
477
  parts.join(" ")
212
478
  ))
213
479
  } else {
@@ -229,7 +495,7 @@ where
229
495
  }
230
496
  }
231
497
  Ok(format!(
232
- "Value::Object(Rc::new(RefCell::new(ObjectMap::from([{}]))))",
498
+ "Value::Object(VmRef::new(ObjectMap::from([{}])))",
233
499
  kv.join(", ")
234
500
  ))
235
501
  }
@@ -331,7 +597,12 @@ fn stmt_contains_jsx(stmt: &tishlang_ast::Statement) -> bool {
331
597
  ExportDeclaration::Named(inner) => stmt_contains_jsx(inner),
332
598
  ExportDeclaration::Default(e) => expr_contains_jsx(e),
333
599
  },
334
- Statement::Import { .. } | Statement::Break { .. } | Statement::Continue { .. } => false,
600
+ Statement::Import { .. }
601
+ | Statement::Break { .. }
602
+ | Statement::Continue { .. }
603
+ | Statement::TypeAlias { .. }
604
+ | Statement::DeclareVar { .. }
605
+ | Statement::DeclareFun { .. } => false,
335
606
  }
336
607
  }
337
608
 
@@ -11,6 +11,9 @@ pub mod runtime;
11
11
 
12
12
  #[cfg(feature = "runtime")]
13
13
  pub use runtime::{
14
- fragment_value, install_thread_local_host, native_create_root, native_use_state, ui_h, ui_text,
15
- with_thread_local_host, HeadlessHost, Host, FRAGMENT_SENTINEL,
14
+ alloc_root_id, current_root_id, drop_host_for_root, fragment_value, install_host_for_root,
15
+ install_thread_local_host, native_create_root, native_use_effect, native_use_memo,
16
+ native_use_state, run_with_current_root, ui_h, ui_text, unregister_root,
17
+ unregister_root_hooks_and_effects, with_host_for_root, with_thread_local_host, HeadlessHost, Host,
18
+ FRAGMENT_SENTINEL, LEGACY_ROOT_ID, RootId,
16
19
  };