@tishlang/tish 1.6.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 (113) hide show
  1. package/Cargo.toml +2 -0
  2. package/README.md +2 -0
  3. package/bin/tish +0 -0
  4. package/crates/js_to_tish/src/error.rs +2 -8
  5. package/crates/js_to_tish/src/transform/expr.rs +128 -137
  6. package/crates/js_to_tish/src/transform/stmt.rs +62 -32
  7. package/crates/tish/Cargo.toml +15 -5
  8. package/crates/tish/src/cargo_native_registry.rs +29 -0
  9. package/crates/tish/src/cli_help.rs +92 -39
  10. package/crates/tish/src/main.rs +172 -86
  11. package/crates/tish/src/repl_completion.rs +3 -3
  12. package/crates/tish/tests/cargo_example_compile.rs +4 -2
  13. package/crates/tish/tests/integration_test.rs +216 -54
  14. package/crates/tish/tests/run_optimize_stdout_parity.rs +3 -7
  15. package/crates/tish/tests/shortcircuit.rs +20 -5
  16. package/crates/tish_ast/src/ast.rs +92 -23
  17. package/crates/tish_build_utils/Cargo.toml +4 -0
  18. package/crates/tish_build_utils/src/lib.rs +136 -8
  19. package/crates/tish_builtins/Cargo.toml +5 -1
  20. package/crates/tish_builtins/src/array.rs +65 -33
  21. package/crates/tish_builtins/src/construct.rs +34 -39
  22. package/crates/tish_builtins/src/globals.rs +42 -26
  23. package/crates/tish_builtins/src/helpers.rs +2 -1
  24. package/crates/tish_builtins/src/lib.rs +5 -5
  25. package/crates/tish_builtins/src/math.rs +5 -3
  26. package/crates/tish_builtins/src/object.rs +3 -2
  27. package/crates/tish_builtins/src/string.rs +144 -22
  28. package/crates/tish_bytecode/src/chunk.rs +0 -1
  29. package/crates/tish_bytecode/src/compiler.rs +173 -71
  30. package/crates/tish_bytecode/src/opcode.rs +24 -6
  31. package/crates/tish_bytecode/src/peephole.rs +2 -2
  32. package/crates/tish_compile/Cargo.toml +1 -0
  33. package/crates/tish_compile/src/codegen.rs +1621 -453
  34. package/crates/tish_compile/src/infer.rs +75 -19
  35. package/crates/tish_compile/src/lib.rs +19 -8
  36. package/crates/tish_compile/src/resolve.rs +278 -137
  37. package/crates/tish_compile/src/types.rs +184 -24
  38. package/crates/tish_compile_js/Cargo.toml +1 -0
  39. package/crates/tish_compile_js/src/codegen.rs +181 -37
  40. package/crates/tish_compile_js/src/lib.rs +3 -1
  41. package/crates/tish_compile_js/src/tests_jsx.rs +30 -6
  42. package/crates/tish_compiler_wasm/src/lib.rs +16 -13
  43. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +69 -59
  44. package/crates/tish_core/Cargo.toml +8 -0
  45. package/crates/tish_core/src/json.rs +107 -56
  46. package/crates/tish_core/src/lib.rs +4 -2
  47. package/crates/tish_core/src/macros.rs +5 -5
  48. package/crates/tish_core/src/uri.rs +9 -6
  49. package/crates/tish_core/src/value.rs +145 -43
  50. package/crates/tish_core/src/vmref.rs +178 -0
  51. package/crates/tish_cranelift/src/link.rs +6 -9
  52. package/crates/tish_cranelift/src/lower.rs +14 -8
  53. package/crates/tish_eval/Cargo.toml +17 -2
  54. package/crates/tish_eval/src/eval.rs +474 -165
  55. package/crates/tish_eval/src/http.rs +61 -0
  56. package/crates/tish_eval/src/lib.rs +12 -8
  57. package/crates/tish_eval/src/natives.rs +136 -38
  58. package/crates/tish_eval/src/promise.rs +14 -8
  59. package/crates/tish_eval/src/timers.rs +28 -19
  60. package/crates/tish_eval/src/value.rs +17 -6
  61. package/crates/tish_eval/src/value_convert.rs +13 -5
  62. package/crates/tish_fmt/src/lib.rs +149 -43
  63. package/crates/tish_lexer/src/lib.rs +232 -63
  64. package/crates/tish_lexer/src/token.rs +10 -6
  65. package/crates/tish_llvm/src/lib.rs +17 -8
  66. package/crates/tish_lsp/Cargo.toml +4 -1
  67. package/crates/tish_lsp/README.md +1 -1
  68. package/crates/tish_lsp/src/builtin_goto.rs +261 -0
  69. package/crates/tish_lsp/src/import_goto.rs +549 -0
  70. package/crates/tish_lsp/src/main.rs +504 -106
  71. package/crates/tish_native/src/build.rs +4 -8
  72. package/crates/tish_native/src/lib.rs +54 -21
  73. package/crates/tish_opt/src/lib.rs +84 -52
  74. package/crates/tish_parser/src/lib.rs +45 -13
  75. package/crates/tish_parser/src/parser.rs +505 -130
  76. package/crates/tish_resolve/Cargo.toml +13 -0
  77. package/crates/tish_resolve/src/lib.rs +3436 -0
  78. package/crates/tish_resolve/src/pos.rs +133 -0
  79. package/crates/tish_runtime/Cargo.toml +68 -3
  80. package/crates/tish_runtime/src/http.rs +1136 -145
  81. package/crates/tish_runtime/src/http_fetch.rs +38 -27
  82. package/crates/tish_runtime/src/http_hyper.rs +418 -0
  83. package/crates/tish_runtime/src/http_prefork.rs +189 -0
  84. package/crates/tish_runtime/src/lib.rs +375 -189
  85. package/crates/tish_runtime/src/promise.rs +199 -40
  86. package/crates/tish_runtime/src/promise_io.rs +2 -1
  87. package/crates/tish_runtime/src/timers.rs +37 -1
  88. package/crates/tish_runtime/src/ws.rs +65 -42
  89. package/crates/tish_runtime/tests/fetch_readable_stream.rs +5 -4
  90. package/crates/tish_ui/src/jsx.rs +317 -27
  91. package/crates/tish_ui/src/lib.rs +5 -2
  92. package/crates/tish_ui/src/runtime/hooks.rs +406 -45
  93. package/crates/tish_ui/src/runtime/mod.rs +36 -9
  94. package/crates/tish_vm/Cargo.toml +15 -5
  95. package/crates/tish_vm/src/vm.rs +725 -281
  96. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +11 -4
  97. package/crates/tish_wasm/src/lib.rs +55 -42
  98. package/crates/tish_wasm_runtime/Cargo.toml +2 -1
  99. package/crates/tish_wasm_runtime/src/lib.rs +1 -1
  100. package/crates/tishlang_cargo_bindgen/Cargo.toml +26 -0
  101. package/crates/tishlang_cargo_bindgen/src/classify.rs +265 -0
  102. package/crates/tishlang_cargo_bindgen/src/discover.rs +120 -0
  103. package/crates/tishlang_cargo_bindgen/src/infer.rs +372 -0
  104. package/crates/tishlang_cargo_bindgen/src/lib.rs +350 -0
  105. package/crates/tishlang_cargo_bindgen/src/main.rs +164 -0
  106. package/crates/tishlang_cargo_bindgen/src/metadata.rs +114 -0
  107. package/justfile +8 -0
  108. package/package.json +1 -1
  109. package/platform/darwin-arm64/tish +0 -0
  110. package/platform/darwin-x64/tish +0 -0
  111. package/platform/linux-arm64/tish +0 -0
  112. package/platform/linux-x64/tish +0 -0
  113. package/platform/win32-x64/tish.exe +0 -0
@@ -0,0 +1,261 @@
1
+ //! Built-in and JSX-intrinsic "go to definition" for the Tish LSP.
2
+ //!
3
+ //! Global / namespace member anchors are loaded from `stdlib/builtins.d.tish` in the `tish`
4
+ //! repository via `// @tish-source <symbol> <rel-path> <1-based-line>` pragmas. The type
5
+ //! surface in that file is the canonical declaration for ambient builtins.
6
+ //!
7
+ //! HTML / SVG intrinsic tag names are still listed here (sorted) for fast lookup; each maps
8
+ //! to the same vnode factory as in the pragma table for `div`.
9
+ //!
10
+ //! Definitions resolve to `file://` URIs only when `TISHLANG_SOURCE_ROOT` is set or the client
11
+ //! passes `tishlangSourceRoot` in LSP `initializationOptions` (VS Code: `tish.tishlangSourceRoot`).
12
+
13
+ use std::collections::HashMap;
14
+ use std::path::Path;
15
+ use std::sync::OnceLock;
16
+
17
+ use regex::Regex;
18
+ use tower_lsp::lsp_types::{Location, Position, Range, Url};
19
+
20
+ /// Stable path relative to the `tish` repository root (where the workspace `Cargo.toml` lives).
21
+ #[derive(Clone, Debug, PartialEq, Eq)]
22
+ pub struct BuiltinDef {
23
+ pub rel_path: String,
24
+ /// 0-based LSP line in the target file.
25
+ pub line: u32,
26
+ /// 0-based UTF-16 code unit offset on that line (ASCII-only targets use byte column).
27
+ pub character: u32,
28
+ }
29
+
30
+ fn is_ident_char(c: char) -> bool {
31
+ c.is_alphanumeric() || c == '_'
32
+ }
33
+
34
+ /// HTML / SVG intrinsic tag names (lowercase) that JSX lowers to `h("tag", …)`; must stay sorted for `binary_search`.
35
+ const HTML_INTRINSIC_TAGS: &[&str] = &[
36
+ "a", "abbr", "address", "area", "article", "aside", "audio", "b", "base", "bdi", "bdo",
37
+ "blockquote", "body", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup",
38
+ "data", "datalist", "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed",
39
+ "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6",
40
+ "head", "header", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "label", "legend",
41
+ "li", "link", "main", "map", "mark", "meta", "meter", "nav", "noscript", "object", "ol",
42
+ "optgroup", "option", "output", "p", "param", "picture", "pre", "progress", "q", "rp", "rt",
43
+ "ruby", "s", "samp", "script", "section", "select", "slot", "small", "source", "span", "strong",
44
+ "style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea",
45
+ "tfoot", "th", "thead", "time", "title", "tr", "track", "u", "ul", "var", "video", "wbr",
46
+ ];
47
+
48
+ static SOURCE_MAP: OnceLock<HashMap<String, BuiltinDef>> = OnceLock::new();
49
+
50
+ /// Parse `// @tish-source <symbol> <rel-path> <1-based-line>` lines (same format as `stdlib/builtins.d.tish`).
51
+ pub fn parse_tish_source_pragmas(src: &str) -> HashMap<String, BuiltinDef> {
52
+ let re = Regex::new(r"(?m)^\s*//\s*@tish-source\s+(\S+)\s+(\S+)\s+(\d+)\s*$")
53
+ .expect("builtin pragma regex");
54
+ let mut m = HashMap::new();
55
+ for cap in re.captures_iter(src) {
56
+ let sym = cap[1].to_string();
57
+ let rel = cap[2].to_string();
58
+ let line_1: u32 = cap[3].parse().unwrap_or(1);
59
+ m.insert(
60
+ sym,
61
+ BuiltinDef {
62
+ rel_path: rel,
63
+ line: line_1.saturating_sub(1),
64
+ character: 0,
65
+ },
66
+ );
67
+ }
68
+ m
69
+ }
70
+
71
+ fn source_map() -> &'static HashMap<String, BuiltinDef> {
72
+ SOURCE_MAP.get_or_init(|| {
73
+ let src = include_str!(concat!(
74
+ env!("CARGO_MANIFEST_DIR"),
75
+ "/../../stdlib/builtins.d.tish"
76
+ ));
77
+ parse_tish_source_pragmas(src)
78
+ })
79
+ }
80
+
81
+ /// If `col` lies on the name of a JSX opening (or closing) tag on this line, returns the span of that name in **character indices** (same convention as [`tower_lsp::lsp_types::Position::character`] for ASCII lines).
82
+ fn jsx_tag_name_char_span(line: &str, col: usize) -> Option<(usize, usize)> {
83
+ let chars: Vec<char> = line.chars().collect();
84
+ if chars.is_empty() {
85
+ return None;
86
+ }
87
+ let col = col.min(chars.len().saturating_sub(1));
88
+ let mut j = col;
89
+ while j > 0 {
90
+ j -= 1;
91
+ if chars[j] == '>' {
92
+ return None;
93
+ }
94
+ if chars[j] == '<' {
95
+ let mut k = j + 1;
96
+ while k < chars.len() && chars[k].is_whitespace() {
97
+ k += 1;
98
+ }
99
+ if k < chars.len() && chars[k] == '/' {
100
+ k += 1;
101
+ while k < chars.len() && chars[k].is_whitespace() {
102
+ k += 1;
103
+ }
104
+ }
105
+ let name_start = k;
106
+ while k < chars.len() {
107
+ let c = chars[k];
108
+ if c.is_whitespace() || c == '>' || c == '/' || c == '{' {
109
+ break;
110
+ }
111
+ if !(c.is_alphanumeric() || c == '_' || c == '-') {
112
+ break;
113
+ }
114
+ k += 1;
115
+ }
116
+ let name_end = k;
117
+ if name_start < name_end && col >= name_start && col < name_end {
118
+ return Some((name_start, name_end));
119
+ }
120
+ return None;
121
+ }
122
+ }
123
+ None
124
+ }
125
+
126
+ fn tag_name_at_span(line: &str, start: usize, end: usize) -> String {
127
+ line.chars()
128
+ .enumerate()
129
+ .filter(|(i, _)| *i >= start && *i < end)
130
+ .map(|(_, c)| c)
131
+ .collect()
132
+ }
133
+
134
+ /// `base.member` when the cursor is on `member` (same line, character-index column as `word_at_position`).
135
+ fn split_property_access(line: &str, col: usize) -> Option<(String, String)> {
136
+ let chars: Vec<char> = line.chars().collect();
137
+ if chars.is_empty() {
138
+ return None;
139
+ }
140
+ let col = col.min(chars.len().saturating_sub(1));
141
+ if !is_ident_char(chars[col]) {
142
+ return None;
143
+ }
144
+ let mut end = col;
145
+ while end + 1 < chars.len() && is_ident_char(chars[end + 1]) {
146
+ end += 1;
147
+ }
148
+ let mut start = col;
149
+ while start > 0 && is_ident_char(chars[start - 1]) {
150
+ start -= 1;
151
+ }
152
+ if start == 0 {
153
+ return None;
154
+ }
155
+ if chars[start - 1] != '.' {
156
+ return None;
157
+ }
158
+ let member: String = chars[start..=end].iter().collect();
159
+ let mut k = start - 2;
160
+ while k > 0 && is_ident_char(chars[k - 1]) {
161
+ k -= 1;
162
+ }
163
+ let base: String = chars[k..start - 1].iter().collect();
164
+ if base.is_empty() {
165
+ return None;
166
+ }
167
+ Some((base, member))
168
+ }
169
+
170
+ fn lookup_dotted(base: &str, member: &str) -> Option<BuiltinDef> {
171
+ let key = format!("{base}.{member}");
172
+ source_map().get(&key).cloned()
173
+ }
174
+
175
+ fn lookup_global(word: &str) -> Option<BuiltinDef> {
176
+ source_map().get(word).cloned()
177
+ }
178
+
179
+ /// Built-in or JSX-intrinsic definition for the identifier at `position`, if any.
180
+ pub fn definition_for_builtin(
181
+ text: &str,
182
+ line: u32,
183
+ character: u32,
184
+ word: &str,
185
+ ) -> Option<BuiltinDef> {
186
+ let line_str = text.lines().nth(line as usize)?;
187
+ let col = character as usize;
188
+
189
+ if let Some((ns, ne)) = jsx_tag_name_char_span(line_str, col) {
190
+ let tag = tag_name_at_span(line_str, ns, ne);
191
+ if tag == word {
192
+ if word == "Fragment" {
193
+ return lookup_global("Fragment");
194
+ }
195
+ if HTML_INTRINSIC_TAGS.binary_search(&word).is_ok() {
196
+ // Intrinsic tags share the same `ui_h` entry point as `div`.
197
+ return lookup_global("div");
198
+ }
199
+ }
200
+ }
201
+
202
+ if let Some((base, member)) = split_property_access(line_str, col) {
203
+ if let Some(d) = lookup_dotted(base.as_str(), member.as_str()) {
204
+ return Some(d);
205
+ }
206
+ }
207
+
208
+ lookup_global(word)
209
+ }
210
+
211
+ pub fn to_file_location(root: &Path, def: &BuiltinDef) -> Option<Location> {
212
+ let path = root.join(&def.rel_path);
213
+ if !path.is_file() {
214
+ return None;
215
+ }
216
+ let uri = Url::from_file_path(&path).ok()?;
217
+ let p = Position {
218
+ line: def.line,
219
+ character: def.character,
220
+ };
221
+ Some(Location {
222
+ uri,
223
+ range: Range { start: p, end: p },
224
+ })
225
+ }
226
+
227
+ #[cfg(test)]
228
+ mod tests {
229
+ use super::*;
230
+
231
+ #[test]
232
+ fn pragma_map_loads_console_log() {
233
+ let d = lookup_global("console").expect("console");
234
+ assert!(d.rel_path.contains("eval.rs"));
235
+ let m = lookup_dotted("console", "log").expect("console.log");
236
+ assert!(m.rel_path.contains("natives.rs"));
237
+ }
238
+
239
+ #[test]
240
+ fn jsx_div_maps_to_ui_h() {
241
+ let text = "let x = <div />";
242
+ let line = 0u32;
243
+ let defn = definition_for_builtin(text, line, 9, "div").expect("div builtin");
244
+ assert!(defn.rel_path.contains("runtime"));
245
+ assert_eq!(defn.line, 40);
246
+ }
247
+
248
+ #[test]
249
+ fn set_timeout_global() {
250
+ let defn =
251
+ definition_for_builtin("setTimeout(0, fn() {})\n", 0, 0, "setTimeout").expect("timer");
252
+ assert_eq!(defn.rel_path, "crates/tish_eval/src/timers.rs");
253
+ }
254
+
255
+ #[test]
256
+ fn console_log_qualified() {
257
+ let text = "console.log(1)";
258
+ let defn = definition_for_builtin(text, 0, 10, "log").expect("console.log");
259
+ assert_eq!(defn.rel_path, "crates/tish_eval/src/natives.rs");
260
+ }
261
+ }