@tishlang/tish 1.0.7 → 1.0.11

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,20 @@
1
+ #[derive(Debug)]
2
+ pub struct CompileError {
3
+ pub message: String,
4
+ }
5
+
6
+ impl CompileError {
7
+ pub fn new(msg: &str) -> Self {
8
+ Self {
9
+ message: msg.to_string(),
10
+ }
11
+ }
12
+ }
13
+
14
+ impl std::fmt::Display for CompileError {
15
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16
+ write!(f, "{}", self.message)
17
+ }
18
+ }
19
+
20
+ impl std::error::Error for CompileError {}
@@ -0,0 +1,82 @@
1
+ //! JS-only call sites that require `new` (Tish has no `new`).
2
+ //! Intrinsic names, validation, and runtime preamble live here — main codegen only dispatches.
3
+
4
+ use tish_ast::{CallArg, Expr};
5
+
6
+ use crate::error::CompileError;
7
+
8
+ /// Built-in calls lowered to `new ...` in the JS emit.
9
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
10
+ pub enum JsIntrinsic {
11
+ WebAudioCreateContext,
12
+ Uint8Array,
13
+ }
14
+
15
+ #[derive(Debug, Default)]
16
+ pub struct JsIntrinsics {
17
+ pub needs_web_audio: bool,
18
+ pub needs_uint8_array: bool,
19
+ }
20
+
21
+ impl JsIntrinsics {
22
+ pub fn new() -> Self {
23
+ Self::default()
24
+ }
25
+
26
+ /// Recognize `webAudioCreateContext()` / `jsUint8Array(n)` and validate arguments.
27
+ pub fn classify_call(callee: &Expr, args: &[CallArg]) -> Result<Option<JsIntrinsic>, CompileError> {
28
+ let Expr::Ident { name, .. } = callee else {
29
+ return Ok(None);
30
+ };
31
+ match name.as_ref() {
32
+ "webAudioCreateContext" => {
33
+ if !args.is_empty() {
34
+ return Err(CompileError::new(
35
+ "webAudioCreateContext() takes no arguments (JS target only)",
36
+ ));
37
+ }
38
+ Ok(Some(JsIntrinsic::WebAudioCreateContext))
39
+ }
40
+ "jsUint8Array" => {
41
+ if args.len() != 1 {
42
+ return Err(CompileError::new(
43
+ "jsUint8Array(length) expects one argument (JS target only)",
44
+ ));
45
+ }
46
+ Ok(Some(JsIntrinsic::Uint8Array))
47
+ }
48
+ _ => Ok(None),
49
+ }
50
+ }
51
+
52
+ pub fn mark(&mut self, kind: JsIntrinsic) {
53
+ match kind {
54
+ JsIntrinsic::WebAudioCreateContext => self.needs_web_audio = true,
55
+ JsIntrinsic::Uint8Array => self.needs_uint8_array = true,
56
+ }
57
+ }
58
+
59
+ pub fn emit_expr(kind: JsIntrinsic, uint8_length_js: &str) -> String {
60
+ match kind {
61
+ JsIntrinsic::WebAudioCreateContext => "(__tishWebAudioCreateContext() ?? null)".to_string(),
62
+ JsIntrinsic::Uint8Array => format!("(__tishUint8Array({}) ?? null)", uint8_length_js),
63
+ }
64
+ }
65
+
66
+ /// Prepend runtime helpers (Uint8Array above AudioContext when both are used).
67
+ pub fn prepend_runtime_preamble(&self, mut output: String) -> String {
68
+ if self.needs_web_audio {
69
+ output = format!(
70
+ "function __tishWebAudioCreateContext(){{ return new AudioContext(); }}\n{}",
71
+ output
72
+ );
73
+ }
74
+ if self.needs_uint8_array {
75
+ output = format!(
76
+ "function __tishUint8Array(n){{ return new Uint8Array(n); }}\n{}",
77
+ output
78
+ );
79
+ }
80
+ output
81
+ }
82
+ }
@@ -0,0 +1,27 @@
1
+ //! Tish to JavaScript transpiler backend.
2
+ //! Uses shared resolve from tish_compile for unified pipeline.
3
+
4
+ mod codegen;
5
+ mod error;
6
+ mod js_intrinsics;
7
+
8
+ #[cfg(test)]
9
+ mod tests_jsx;
10
+
11
+ pub use codegen::{compile_project_with_jsx, compile_with_jsx, JsxMode};
12
+ pub use error::CompileError;
13
+
14
+ /// Default JSX mode lowers to Lattish-style calls (implementation detail). Import what you use from
15
+ /// `lattish` (e.g. `useState`, `createRoot`); the merged bundle includes the JSX runtime from that
16
+ /// module. JSX-only files can use `import {} from "lattish"` to pull it in without bindings.
17
+ pub fn compile(program: &tish_ast::Program, optimize: bool) -> Result<String, CompileError> {
18
+ compile_with_jsx(program, optimize, JsxMode::LattishH)
19
+ }
20
+
21
+ pub fn compile_project(
22
+ entry_path: &std::path::Path,
23
+ project_root: Option<&std::path::Path>,
24
+ optimize: bool,
25
+ ) -> Result<String, CompileError> {
26
+ compile_project_with_jsx(entry_path, project_root, optimize, JsxMode::LattishH)
27
+ }
@@ -0,0 +1,32 @@
1
+ #[cfg(test)]
2
+ mod tests {
3
+ use tish_parser::parse;
4
+
5
+ use crate::{compile_with_jsx, JsxMode};
6
+
7
+ #[test]
8
+ fn lattish_jsx_emits_h_with_children_array() {
9
+ let src = r#"fn X() { return <div class="a">{"hi"}</div> }"#;
10
+ let program = parse(src).unwrap();
11
+ let js = compile_with_jsx(&program, false, JsxMode::LattishH).unwrap();
12
+ assert!(js.contains("h(\"div\", { class: \"a\" }, [\"hi\"])"), "{}", js);
13
+ assert!(!js.contains("function __h("));
14
+ }
15
+
16
+ #[test]
17
+ fn fragment_lattish_uses_fragment_symbol() {
18
+ let src = "fn X() { return <><b>{\"1\"}</b></> }";
19
+ let program = parse(src).unwrap();
20
+ let js = compile_with_jsx(&program, false, JsxMode::LattishH).unwrap();
21
+ assert!(js.contains("h(Fragment, null, ["));
22
+ }
23
+
24
+ #[test]
25
+ fn vdom_emits_vdom_h() {
26
+ let src = r#"fn X() { return <p/> }"#;
27
+ let program = parse(src).unwrap();
28
+ let js = compile_with_jsx(&program, false, JsxMode::Vdom).unwrap();
29
+ assert!(js.contains("__vdom_h(\"p\", null, [])"), "{}", &js[..600.min(js.len())]);
30
+ assert!(js.contains("__lattishVdomPatch"));
31
+ }
32
+ }
@@ -0,0 +1,19 @@
1
+ [package]
2
+ name = "tish_compiler_wasm"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Tish compiler as WASM for browser (parse + bytecode + JS)"
6
+
7
+ [lib]
8
+ crate-type = ["cdylib"]
9
+
10
+ [dependencies]
11
+ base64 = "0.22"
12
+ serde_json = "1.0"
13
+ wasm-bindgen = "0.2"
14
+
15
+ tish_ast = { path = "../tish_ast" }
16
+ tish_bytecode = { path = "../tish_bytecode" }
17
+ tish_compile_js = { path = "../tish_compile_js" }
18
+ tish_opt = { path = "../tish_opt" }
19
+ tish_parser = { path = "../tish_parser" }
@@ -0,0 +1,55 @@
1
+ //! Tish compiler exposed to JS via wasm-bindgen.
2
+ //! Compiles single source string → bytecode (base64) or JS. Used by playground, REPL, try-it pages.
3
+ //!
4
+ //! `compile_to_js` / `compile_to_js_with_imports` use Lattish-style JSX lowering. Prepend a compiled
5
+ //! **Lattish.tish** runtime (same as playground `lattish-runtime.js`) so the iframe/script scope has
6
+ //! hooks and the JSX helpers; source files do not need to import the JSX helper by name.
7
+
8
+ mod resolve_virtual;
9
+
10
+ use base64::Engine;
11
+ use resolve_virtual::{detect_cycles_virtual, merge_modules_virtual, resolve_virtual};
12
+ use std::collections::HashMap;
13
+ use tish_compile_js::JsxMode;
14
+ use wasm_bindgen::prelude::*;
15
+
16
+ #[wasm_bindgen]
17
+ pub fn compile_to_bytecode(source: &str) -> Result<String, JsValue> {
18
+ let program = tish_parser::parse(source.trim()).map_err(|e| JsValue::from_str(&e.to_string()))?;
19
+ let program = tish_opt::optimize(&program);
20
+ let chunk = tish_bytecode::compile(&program).map_err(|e| JsValue::from_str(&e.to_string()))?;
21
+ Ok(base64::engine::general_purpose::STANDARD.encode(tish_bytecode::serialize(&chunk)))
22
+ }
23
+
24
+ #[wasm_bindgen]
25
+ pub fn compile_to_js(source: &str) -> Result<String, JsValue> {
26
+ let program = tish_parser::parse(source.trim()).map_err(|e| JsValue::from_str(&e.to_string()))?;
27
+ tish_compile_js::compile_with_jsx(&program, true, JsxMode::LattishH)
28
+ .map_err(|e| JsValue::from_str(&e.message))
29
+ }
30
+
31
+ #[wasm_bindgen]
32
+ pub fn compile_to_bytecode_with_imports(entry_path: &str, files_json: &str) -> Result<String, JsValue> {
33
+ let files: HashMap<String, String> = serde_json::from_str(files_json)
34
+ .map_err(|e| JsValue::from_str(&format!("Invalid files JSON: {}", e)))?;
35
+ let modules = resolve_virtual(entry_path, &files)
36
+ .map_err(|e| JsValue::from_str(&e))?;
37
+ detect_cycles_virtual(&modules).map_err(|e| JsValue::from_str(&e))?;
38
+ let program = merge_modules_virtual(modules).map_err(|e| JsValue::from_str(&e))?;
39
+ let program = tish_opt::optimize(&program);
40
+ let chunk = tish_bytecode::compile(&program).map_err(|e| JsValue::from_str(&e.to_string()))?;
41
+ Ok(base64::engine::general_purpose::STANDARD.encode(tish_bytecode::serialize(&chunk)))
42
+ }
43
+
44
+ #[wasm_bindgen]
45
+ pub fn compile_to_js_with_imports(entry_path: &str, files_json: &str) -> Result<String, JsValue> {
46
+ let files: HashMap<String, String> = serde_json::from_str(files_json)
47
+ .map_err(|e| JsValue::from_str(&format!("Invalid files JSON: {}", e)))?;
48
+ let modules = resolve_virtual(entry_path, &files)
49
+ .map_err(|e| JsValue::from_str(&e))?;
50
+ detect_cycles_virtual(&modules).map_err(|e| JsValue::from_str(&e))?;
51
+ let program = merge_modules_virtual(modules).map_err(|e| JsValue::from_str(&e))?;
52
+ let program = tish_opt::optimize(&program);
53
+ tish_compile_js::compile_with_jsx(&program, true, JsxMode::LattishH)
54
+ .map_err(|e| JsValue::from_str(&e.message))
55
+ }