@tishlang/tish 1.9.2 → 1.12.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.
- package/bin/tish +0 -0
- package/crates/js_to_tish/src/transform/expr.rs +8 -6
- package/crates/js_to_tish/src/transform/stmt.rs +12 -13
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cargo_native_registry.rs +4 -1
- package/crates/tish/src/cli_help.rs +9 -1
- package/crates/tish/src/main.rs +66 -11
- package/crates/tish/tests/integration_test.rs +145 -7
- package/crates/tish_ast/src/ast.rs +3 -9
- package/crates/tish_build_utils/src/lib.rs +74 -23
- package/crates/tish_builtins/src/array.rs +2 -3
- package/crates/tish_builtins/src/construct.rs +15 -28
- package/crates/tish_builtins/src/globals.rs +18 -16
- package/crates/tish_builtins/src/helpers.rs +1 -4
- package/crates/tish_builtins/src/lib.rs +1 -0
- package/crates/tish_builtins/src/math.rs +7 -0
- package/crates/tish_builtins/src/object.rs +10 -10
- package/crates/tish_builtins/src/string.rs +27 -3
- package/crates/tish_builtins/src/symbol.rs +83 -0
- package/crates/tish_compile/src/codegen.rs +324 -158
- package/crates/tish_compile/src/lib.rs +39 -7
- package/crates/tish_compile/src/resolve.rs +191 -6
- package/crates/tish_compile/src/types.rs +6 -6
- package/crates/tish_compile_js/src/codegen.rs +8 -5
- package/crates/tish_core/src/console_style.rs +9 -0
- package/crates/tish_core/src/json.rs +17 -7
- package/crates/tish_core/src/macros.rs +2 -2
- package/crates/tish_core/src/value.rs +213 -4
- package/crates/tish_cranelift/src/link.rs +1 -1
- package/crates/tish_cranelift_runtime/Cargo.toml +4 -0
- package/crates/tish_eval/src/eval.rs +135 -73
- package/crates/tish_eval/src/http.rs +18 -12
- package/crates/tish_eval/src/lib.rs +29 -0
- package/crates/tish_eval/src/regex.rs +1 -1
- package/crates/tish_eval/src/value.rs +89 -4
- package/crates/tish_eval/src/value_convert.rs +30 -8
- package/crates/tish_fmt/src/lib.rs +4 -1
- package/crates/tish_lexer/src/lib.rs +7 -2
- package/crates/tish_llvm/src/lib.rs +2 -2
- package/crates/tish_lsp/src/builtin_goto.rs +111 -10
- package/crates/tish_lsp/src/import_goto.rs +35 -22
- package/crates/tish_lsp/src/main.rs +118 -85
- package/crates/tish_native/src/build.rs +270 -24
- package/crates/tish_native/src/config.rs +48 -0
- package/crates/tish_native/src/lib.rs +139 -12
- package/crates/tish_parser/src/lib.rs +5 -2
- package/crates/tish_parser/src/parser.rs +45 -75
- package/crates/tish_pg/src/error.rs +1 -1
- package/crates/tish_pg/src/lib.rs +61 -73
- package/crates/tish_resolve/src/lib.rs +283 -158
- package/crates/tish_resolve/src/pos.rs +10 -2
- package/crates/tish_runtime/Cargo.toml +3 -0
- package/crates/tish_runtime/src/http.rs +39 -39
- package/crates/tish_runtime/src/http_fetch.rs +12 -12
- package/crates/tish_runtime/src/lib.rs +35 -44
- package/crates/tish_runtime/src/native_promise.rs +0 -11
- package/crates/tish_runtime/src/promise.rs +14 -1
- package/crates/tish_runtime/src/promise_io.rs +1 -4
- package/crates/tish_runtime/src/timers.rs +12 -7
- package/crates/tish_runtime/src/ws.rs +40 -27
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +10 -8
- package/crates/tish_ui/src/jsx.rs +6 -4
- package/crates/tish_ui/src/lib.rs +5 -4
- package/crates/tish_ui/src/runtime/hooks.rs +123 -37
- package/crates/tish_ui/src/runtime/mod.rs +21 -41
- package/crates/tish_vm/Cargo.toml +2 -0
- package/crates/tish_vm/src/vm.rs +258 -153
- package/crates/tish_wasm/src/lib.rs +60 -7
- package/crates/tish_wasm_runtime/Cargo.toml +10 -1
- package/crates/tish_wasm_runtime/src/gpu.rs +413 -0
- package/crates/tish_wasm_runtime/src/lib.rs +7 -1
- package/crates/tishlang_cargo_bindgen/src/classify.rs +1 -3
- package/crates/tishlang_cargo_bindgen/src/discover.rs +10 -5
- package/crates/tishlang_cargo_bindgen/src/infer.rs +18 -8
- package/crates/tishlang_cargo_bindgen/src/lib.rs +25 -26
- package/crates/tishlang_cargo_bindgen/src/main.rs +41 -38
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +4 -1
- package/justfile +3 -3
- package/package.json +1 -1
- 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
|
@@ -7,17 +7,27 @@ mod infer;
|
|
|
7
7
|
mod resolve;
|
|
8
8
|
mod types;
|
|
9
9
|
|
|
10
|
+
/// How generated Rust is linked (desktop binary vs embedded iOS staticlib).
|
|
11
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
|
12
|
+
pub enum NativeEmitMode {
|
|
13
|
+
#[default]
|
|
14
|
+
DesktopBin,
|
|
15
|
+
/// `[lib] crate-type = ["staticlib"]` — no `fn main()`, host calls `tish_ios_launch`.
|
|
16
|
+
EmbeddedLib,
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
pub use codegen::CompileError;
|
|
11
20
|
pub use codegen::{
|
|
12
|
-
compile, compile_project, compile_project_full,
|
|
13
|
-
compile_with_native_modules,
|
|
21
|
+
compile, compile_project, compile_project_full, compile_project_full_emit,
|
|
22
|
+
compile_with_features, compile_with_native_modules, compile_with_native_modules_emit,
|
|
23
|
+
compile_with_project_root,
|
|
14
24
|
};
|
|
15
25
|
pub use resolve::{
|
|
16
|
-
cargo_export_fn_name, compute_native_build_artifacts, detect_cycles,
|
|
17
|
-
extract_native_import_features, format_rust_dependencies_toml,
|
|
18
|
-
has_external_native_imports, has_native_imports,
|
|
19
|
-
is_builtin_native_spec, is_cargo_native_spec, is_native_import,
|
|
20
|
-
normalize_builtin_spec, read_project_tish_config,
|
|
26
|
+
cargo_export_fn_name, compute_native_build_artifacts, detect_cycles, ensure_tish_canvas_module,
|
|
27
|
+
export_name_to_rust_ident, extract_native_import_features, format_rust_dependencies_toml,
|
|
28
|
+
generate_native_wrapper_rs, has_external_native_imports, has_native_imports,
|
|
29
|
+
infer_native_module_exports, is_builtin_native_spec, is_cargo_native_spec, is_native_import,
|
|
30
|
+
merge_modules, normalize_builtin_spec, program_uses_document, read_project_tish_config,
|
|
21
31
|
resolve_bare_spec, resolve_native_modules, resolve_project, resolve_project_from_stdin,
|
|
22
32
|
MergedProgram, NativeBuildArtifacts, NativeModuleInit, ResolvedNativeModule,
|
|
23
33
|
};
|
|
@@ -106,6 +116,28 @@ fn factory() {
|
|
|
106
116
|
);
|
|
107
117
|
}
|
|
108
118
|
|
|
119
|
+
/// `value_call` must take `&Value` to a **local** (`let _callee = (<expr>).clone(); … &_callee`):
|
|
120
|
+
/// `&<temporary>` can dangle in release, and `let _callee = <ident>` would move globals like `Symbol`.
|
|
121
|
+
#[test]
|
|
122
|
+
fn native_emit_value_call_materializes_callee() {
|
|
123
|
+
use std::path::PathBuf;
|
|
124
|
+
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
125
|
+
let path = manifest.join("../../tests/core/symbol.tish").canonicalize().unwrap();
|
|
126
|
+
let (rust, _, _, _) = compile_project_full(&path, path.parent(), &[], true).unwrap();
|
|
127
|
+
assert!(
|
|
128
|
+
rust.contains("let _callee = (tishlang_runtime::get_index"),
|
|
129
|
+
"fixture should bracket-call via get_index with callee stored in a local"
|
|
130
|
+
);
|
|
131
|
+
assert!(
|
|
132
|
+
!rust.contains("let _callee = &tishlang_runtime::get_index"),
|
|
133
|
+
"expected callee materialization, found reference-to-temporary pattern"
|
|
134
|
+
);
|
|
135
|
+
assert!(
|
|
136
|
+
rust.contains("tishlang_runtime::value_call"),
|
|
137
|
+
"expected value_call via runtime re-export for nested Cargo builds"
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
109
141
|
#[test]
|
|
110
142
|
fn loop_var_decl_clone_via_project_full() {
|
|
111
143
|
// With the inference pass, `let outerVar = 42` is inferred as f64 (Copy) — no clone needed.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
use std::collections::{HashMap, HashSet};
|
|
5
5
|
use std::path::{Path, PathBuf};
|
|
6
6
|
use std::sync::Arc;
|
|
7
|
-
use tishlang_ast::{ExportDeclaration, Expr, ImportSpecifier, Program, Statement};
|
|
7
|
+
use tishlang_ast::{ExportDeclaration, Expr, ImportSpecifier, MemberProp, Program, Statement, CallArg};
|
|
8
8
|
|
|
9
9
|
/// Resolved native module: crate path and init expression.
|
|
10
10
|
#[derive(Debug, Clone)]
|
|
@@ -67,8 +67,10 @@ pub fn normalize_builtin_spec(spec: &str) -> Option<String> {
|
|
|
67
67
|
|
|
68
68
|
/// Built-in modules that come from tishlang_runtime, not from package.json.
|
|
69
69
|
pub fn is_builtin_native_spec(spec: &str) -> bool {
|
|
70
|
-
matches!(
|
|
71
|
-
|
|
70
|
+
matches!(
|
|
71
|
+
spec,
|
|
72
|
+
"tish:fs" | "tish:http" | "tish:timers" | "tish:process" | "tish:ws"
|
|
73
|
+
) || matches!(spec, "fs" | "http" | "timers" | "process" | "ws")
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/// Resolve all native imports in a merged program via package.json lookup.
|
|
@@ -112,6 +114,188 @@ pub fn resolve_native_modules(
|
|
|
112
114
|
Ok(modules)
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
/// True when merged Tish source references the browser global `document` (e.g. juke-cards).
|
|
118
|
+
pub fn program_uses_document(program: &Program) -> bool {
|
|
119
|
+
use tishlang_ast::{ArrayElement, ArrowBody, JsxAttrValue, JsxChild, JsxProp, ObjectProp};
|
|
120
|
+
|
|
121
|
+
fn expr_uses_document(e: &Expr) -> bool {
|
|
122
|
+
match e {
|
|
123
|
+
Expr::Ident { name, .. } => name.as_ref() == "document",
|
|
124
|
+
Expr::Literal { .. } | Expr::NativeModuleLoad { .. } => false,
|
|
125
|
+
Expr::Binary { left, right, .. } => {
|
|
126
|
+
expr_uses_document(left) || expr_uses_document(right)
|
|
127
|
+
}
|
|
128
|
+
Expr::Unary { operand, .. } | Expr::TypeOf { operand, .. } => {
|
|
129
|
+
expr_uses_document(operand)
|
|
130
|
+
}
|
|
131
|
+
Expr::Call { callee, args, .. } => {
|
|
132
|
+
expr_uses_document(callee)
|
|
133
|
+
|| args.iter().any(|a| match a {
|
|
134
|
+
CallArg::Expr(e) | CallArg::Spread(e) => expr_uses_document(e),
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
Expr::New { callee, args, .. } => {
|
|
138
|
+
expr_uses_document(callee)
|
|
139
|
+
|| args.iter().any(|a| match a {
|
|
140
|
+
CallArg::Expr(e) | CallArg::Spread(e) => expr_uses_document(e),
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
Expr::Member { object, prop, .. } => {
|
|
144
|
+
expr_uses_document(object)
|
|
145
|
+
|| if let MemberProp::Expr(e) = prop {
|
|
146
|
+
expr_uses_document(e)
|
|
147
|
+
} else {
|
|
148
|
+
false
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
Expr::Index { object, index, .. } => {
|
|
152
|
+
expr_uses_document(object) || expr_uses_document(index)
|
|
153
|
+
}
|
|
154
|
+
Expr::Conditional {
|
|
155
|
+
cond,
|
|
156
|
+
then_branch,
|
|
157
|
+
else_branch,
|
|
158
|
+
..
|
|
159
|
+
} => {
|
|
160
|
+
expr_uses_document(cond)
|
|
161
|
+
|| expr_uses_document(then_branch)
|
|
162
|
+
|| expr_uses_document(else_branch)
|
|
163
|
+
}
|
|
164
|
+
Expr::NullishCoalesce { left, right, .. } => {
|
|
165
|
+
expr_uses_document(left) || expr_uses_document(right)
|
|
166
|
+
}
|
|
167
|
+
Expr::Array { elements, .. } => elements.iter().any(|el| match el {
|
|
168
|
+
ArrayElement::Expr(e) | ArrayElement::Spread(e) => expr_uses_document(e),
|
|
169
|
+
}),
|
|
170
|
+
Expr::Object { props, .. } => props.iter().any(|p| match p {
|
|
171
|
+
ObjectProp::KeyValue(_, e) | ObjectProp::Spread(e) => expr_uses_document(e),
|
|
172
|
+
}),
|
|
173
|
+
Expr::Assign { value, .. }
|
|
174
|
+
| Expr::CompoundAssign { value, .. }
|
|
175
|
+
| Expr::LogicalAssign { value, .. }
|
|
176
|
+
| Expr::MemberAssign { value, .. }
|
|
177
|
+
| Expr::IndexAssign { value, .. } => expr_uses_document(value),
|
|
178
|
+
Expr::PostfixInc { .. }
|
|
179
|
+
| Expr::PostfixDec { .. }
|
|
180
|
+
| Expr::PrefixInc { .. }
|
|
181
|
+
| Expr::PrefixDec { .. } => false,
|
|
182
|
+
Expr::ArrowFunction { body, .. } => match body {
|
|
183
|
+
ArrowBody::Expr(e) => expr_uses_document(e),
|
|
184
|
+
ArrowBody::Block(s) => stmt_uses_document(s),
|
|
185
|
+
},
|
|
186
|
+
Expr::TemplateLiteral { exprs, .. } => exprs.iter().any(expr_uses_document),
|
|
187
|
+
Expr::Await { operand, .. } => expr_uses_document(operand),
|
|
188
|
+
Expr::JsxElement { props, children, .. } => {
|
|
189
|
+
props.iter().any(|p| match p {
|
|
190
|
+
JsxProp::Attr { value, .. } => match value {
|
|
191
|
+
JsxAttrValue::Expr(e) => expr_uses_document(e),
|
|
192
|
+
JsxAttrValue::String(_) | JsxAttrValue::ImplicitTrue => false,
|
|
193
|
+
},
|
|
194
|
+
JsxProp::Spread(e) => expr_uses_document(e),
|
|
195
|
+
}) || children.iter().any(|c| match c {
|
|
196
|
+
JsxChild::Expr(e) => expr_uses_document(e),
|
|
197
|
+
JsxChild::Text(_) => false,
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
Expr::JsxFragment { children, .. } => children.iter().any(|c| match c {
|
|
201
|
+
JsxChild::Expr(e) => expr_uses_document(e),
|
|
202
|
+
JsxChild::Text(_) => false,
|
|
203
|
+
}),
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
fn stmt_uses_document(s: &Statement) -> bool {
|
|
208
|
+
match s {
|
|
209
|
+
Statement::VarDecl { init, .. } => init.as_ref().is_some_and(|e| expr_uses_document(e)),
|
|
210
|
+
Statement::VarDeclDestructure { init, .. } => expr_uses_document(init),
|
|
211
|
+
Statement::ExprStmt { expr, .. } => expr_uses_document(expr),
|
|
212
|
+
Statement::Return { value, .. } => value.as_ref().is_some_and(|e| expr_uses_document(e)),
|
|
213
|
+
Statement::Throw { value, .. } => expr_uses_document(value),
|
|
214
|
+
Statement::If {
|
|
215
|
+
cond,
|
|
216
|
+
then_branch,
|
|
217
|
+
else_branch,
|
|
218
|
+
..
|
|
219
|
+
} => {
|
|
220
|
+
expr_uses_document(cond)
|
|
221
|
+
|| stmt_uses_document(then_branch)
|
|
222
|
+
|| else_branch
|
|
223
|
+
.as_ref()
|
|
224
|
+
.is_some_and(|b| stmt_uses_document(b.as_ref()))
|
|
225
|
+
}
|
|
226
|
+
Statement::While { cond, body, .. }
|
|
227
|
+
| Statement::DoWhile { cond, body, .. } => {
|
|
228
|
+
expr_uses_document(cond) || stmt_uses_document(body)
|
|
229
|
+
}
|
|
230
|
+
Statement::For { init, cond, update, body, .. } => {
|
|
231
|
+
init.as_ref().is_some_and(|s| stmt_uses_document(s.as_ref()))
|
|
232
|
+
|| cond.as_ref().is_some_and(|e| expr_uses_document(e))
|
|
233
|
+
|| update.as_ref().is_some_and(|e| expr_uses_document(e))
|
|
234
|
+
|| stmt_uses_document(body)
|
|
235
|
+
}
|
|
236
|
+
Statement::ForOf { iterable, body, .. } => {
|
|
237
|
+
expr_uses_document(iterable) || stmt_uses_document(body)
|
|
238
|
+
}
|
|
239
|
+
Statement::Switch {
|
|
240
|
+
expr,
|
|
241
|
+
cases,
|
|
242
|
+
default_body,
|
|
243
|
+
..
|
|
244
|
+
} => {
|
|
245
|
+
expr_uses_document(expr)
|
|
246
|
+
|| cases.iter().any(|(e, stmts)| {
|
|
247
|
+
e.as_ref().is_some_and(|e| expr_uses_document(e))
|
|
248
|
+
|| stmts.iter().any(stmt_uses_document)
|
|
249
|
+
})
|
|
250
|
+
|| default_body
|
|
251
|
+
.as_ref()
|
|
252
|
+
.is_some_and(|stmts| stmts.iter().any(stmt_uses_document))
|
|
253
|
+
}
|
|
254
|
+
Statement::Block { statements, .. } => statements.iter().any(stmt_uses_document),
|
|
255
|
+
Statement::FunDecl { body, .. } => stmt_uses_document(body),
|
|
256
|
+
Statement::Try {
|
|
257
|
+
body,
|
|
258
|
+
catch_body,
|
|
259
|
+
finally_body,
|
|
260
|
+
..
|
|
261
|
+
} => {
|
|
262
|
+
stmt_uses_document(body)
|
|
263
|
+
|| catch_body
|
|
264
|
+
.as_ref()
|
|
265
|
+
.is_some_and(|b| stmt_uses_document(b.as_ref()))
|
|
266
|
+
|| finally_body
|
|
267
|
+
.as_ref()
|
|
268
|
+
.is_some_and(|b| stmt_uses_document(b.as_ref()))
|
|
269
|
+
}
|
|
270
|
+
Statement::Import { .. }
|
|
271
|
+
| Statement::Export { .. }
|
|
272
|
+
| Statement::Break { .. }
|
|
273
|
+
| Statement::Continue { .. }
|
|
274
|
+
| Statement::TypeAlias { .. }
|
|
275
|
+
| Statement::DeclareVar { .. }
|
|
276
|
+
| Statement::DeclareFun { .. } => false,
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
program.statements.iter().any(stmt_uses_document)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/// When Tish uses bare `document`, link `tish-canvas` even without `import from 'tish:canvas'`.
|
|
284
|
+
pub fn ensure_tish_canvas_module(
|
|
285
|
+
native_modules: &mut Vec<ResolvedNativeModule>,
|
|
286
|
+
project_root: &Path,
|
|
287
|
+
) -> Result<(), String> {
|
|
288
|
+
if native_modules
|
|
289
|
+
.iter()
|
|
290
|
+
.any(|m| m.crate_name == "tish_canvas" || m.package_name == "tish-canvas")
|
|
291
|
+
{
|
|
292
|
+
return Ok(());
|
|
293
|
+
}
|
|
294
|
+
let m = resolve_native_module("tish:canvas", project_root)?;
|
|
295
|
+
native_modules.push(m);
|
|
296
|
+
Ok(())
|
|
297
|
+
}
|
|
298
|
+
|
|
115
299
|
/// True for `cargo:…` specs (Cargo-backed imports; Rust native backend only).
|
|
116
300
|
pub fn is_cargo_native_spec(spec: &str) -> bool {
|
|
117
301
|
spec.starts_with("cargo:")
|
|
@@ -723,11 +907,11 @@ fn load_module_recursive(
|
|
|
723
907
|
/// - fs, http, timers, process, ws (Node-compatible aliases for tish:*)
|
|
724
908
|
/// - tish:egui, tish:polars, etc.
|
|
725
909
|
/// - cargo:… (Cargo `rustDependencies` + generated wrapper; Rust native backend)
|
|
726
|
-
///
|
|
910
|
+
///
|
|
911
|
+
/// Scoped npm packages (`@scope/pkg`) are merged as Tish source unless imported via `tish:…`.
|
|
727
912
|
pub fn is_native_import(spec: &str) -> bool {
|
|
728
913
|
spec.starts_with("tish:")
|
|
729
914
|
|| spec.starts_with("cargo:")
|
|
730
|
-
|| spec.starts_with('@')
|
|
731
915
|
|| matches!(spec, "fs" | "http" | "timers" | "process" | "ws")
|
|
732
916
|
}
|
|
733
917
|
|
|
@@ -774,7 +958,8 @@ fn resolve_package_root_to_entry(pkg_root: &Path, spec: &str) -> Option<PathBuf>
|
|
|
774
958
|
pub fn resolve_bare_spec(spec: &str, from_dir: &Path, _project_root: &Path) -> Option<PathBuf> {
|
|
775
959
|
let mut search = from_dir.to_path_buf();
|
|
776
960
|
loop {
|
|
777
|
-
if let Some(p) =
|
|
961
|
+
if let Some(p) =
|
|
962
|
+
resolve_package_root_to_entry(&search.join("node_modules").join(spec), spec)
|
|
778
963
|
{
|
|
779
964
|
return Some(p);
|
|
780
965
|
}
|
|
@@ -83,9 +83,9 @@ impl RustType {
|
|
|
83
83
|
RustType::Value
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
|
-
TypeAnnotation::Array(elem) =>
|
|
87
|
-
Self::from_annotation_with_aliases(elem, aliases)
|
|
88
|
-
|
|
86
|
+
TypeAnnotation::Array(elem) => {
|
|
87
|
+
RustType::Vec(Box::new(Self::from_annotation_with_aliases(elem, aliases)))
|
|
88
|
+
}
|
|
89
89
|
TypeAnnotation::Object(fields) => {
|
|
90
90
|
let typed_fields: Vec<_> = fields
|
|
91
91
|
.iter()
|
|
@@ -115,9 +115,9 @@ impl RustType {
|
|
|
115
115
|
|t| !matches!(t, TypeAnnotation::Simple(s) if s.as_ref() == "null"),
|
|
116
116
|
);
|
|
117
117
|
if let Some(inner) = non_null {
|
|
118
|
-
return RustType::Option(Box::new(
|
|
119
|
-
|
|
120
|
-
));
|
|
118
|
+
return RustType::Option(Box::new(Self::from_annotation_with_aliases(
|
|
119
|
+
inner, aliases,
|
|
120
|
+
)));
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
}
|
|
@@ -72,7 +72,11 @@ impl Codegen {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
fn output_line(&self) -> u32 {
|
|
75
|
-
self.output
|
|
75
|
+
self.output
|
|
76
|
+
.as_bytes()
|
|
77
|
+
.iter()
|
|
78
|
+
.filter(|&&b| b == b'\n')
|
|
79
|
+
.count() as u32
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
fn escape_ident(s: &str) -> String {
|
|
@@ -779,7 +783,8 @@ fn compile_project_js_inner(
|
|
|
779
783
|
let modules = tishlang_compile::resolve_project(entry_path, project_root)
|
|
780
784
|
.map_err(|e| CompileError { message: e })?;
|
|
781
785
|
tishlang_compile::detect_cycles(&modules).map_err(|e| CompileError { message: e })?;
|
|
782
|
-
let merged =
|
|
786
|
+
let merged =
|
|
787
|
+
tishlang_compile::merge_modules(modules).map_err(|e| CompileError { message: e })?;
|
|
783
788
|
let program = if optimize {
|
|
784
789
|
tishlang_opt::optimize(&merged.program)
|
|
785
790
|
} else {
|
|
@@ -862,7 +867,5 @@ pub fn compile_project_with_jsx(
|
|
|
862
867
|
} else {
|
|
863
868
|
format!("{stem}.js")
|
|
864
869
|
};
|
|
865
|
-
Ok(
|
|
866
|
-
compile_project_js_inner(entry_path, project_root, optimize, false, &out_name)?.js,
|
|
867
|
-
)
|
|
870
|
+
Ok(compile_project_js_inner(entry_path, project_root, optimize, false, &out_name)?.js)
|
|
868
871
|
}
|
|
@@ -84,6 +84,7 @@ fn format_value_styled_inner(value: &Value, colors: bool, quote_strings: bool) -
|
|
|
84
84
|
Value::Object(obj) => {
|
|
85
85
|
let inner: Vec<String> = obj
|
|
86
86
|
.borrow()
|
|
87
|
+
.strings
|
|
87
88
|
.iter()
|
|
88
89
|
.map(|(k, v)| {
|
|
89
90
|
format!(
|
|
@@ -96,6 +97,14 @@ fn format_value_styled_inner(value: &Value, colors: bool, quote_strings: bool) -
|
|
|
96
97
|
let sep = format!("{PUNCT}, {RESET}");
|
|
97
98
|
format!("{PUNCT}{{{RESET} {} {PUNCT}}}{RESET}", inner.join(&sep))
|
|
98
99
|
}
|
|
100
|
+
Value::Symbol(s) => {
|
|
101
|
+
let body = s
|
|
102
|
+
.description
|
|
103
|
+
.as_ref()
|
|
104
|
+
.map(|d| d.as_ref())
|
|
105
|
+
.unwrap_or("");
|
|
106
|
+
format!("{SPECIAL}Symbol({body}){RESET}")
|
|
107
|
+
}
|
|
99
108
|
Value::Function(_) => format!("{SPECIAL}[Function]{RESET}"),
|
|
100
109
|
Value::Promise(_) => format!("{SPECIAL}[object Promise]{RESET}"),
|
|
101
110
|
Value::Opaque(o) => format!("{SPECIAL}[object {}]{RESET}", o.type_name()),
|
|
@@ -70,8 +70,8 @@ pub fn json_stringify_into(buf: &mut String, value: &Value) {
|
|
|
70
70
|
let borrowed = obj.borrow();
|
|
71
71
|
// Sort keys for deterministic output. Pre-allocate to avoid
|
|
72
72
|
// a fresh `Vec` realloc inside `keys().collect()`.
|
|
73
|
-
let mut keys: Vec<&Arc<str>> = Vec::with_capacity(borrowed.len());
|
|
74
|
-
keys.extend(borrowed.keys());
|
|
73
|
+
let mut keys: Vec<&Arc<str>> = Vec::with_capacity(borrowed.strings.len());
|
|
74
|
+
keys.extend(borrowed.strings.keys());
|
|
75
75
|
keys.sort_unstable_by(|a, b| a.as_ref().cmp(b.as_ref()));
|
|
76
76
|
buf.push('{');
|
|
77
77
|
for (i, key) in keys.into_iter().enumerate() {
|
|
@@ -81,11 +81,13 @@ pub fn json_stringify_into(buf: &mut String, value: &Value) {
|
|
|
81
81
|
buf.push('"');
|
|
82
82
|
escape_json_string_into(buf, key);
|
|
83
83
|
buf.push_str("\":");
|
|
84
|
-
json_stringify_into(buf, borrowed.get(key).unwrap());
|
|
84
|
+
json_stringify_into(buf, borrowed.strings.get(key).unwrap());
|
|
85
85
|
}
|
|
86
86
|
buf.push('}');
|
|
87
87
|
}
|
|
88
|
-
Value::Function(_) | Value::Promise(_) | Value::Opaque(_)
|
|
88
|
+
Value::Function(_) | Value::Promise(_) | Value::Opaque(_) | Value::Symbol(_) => {
|
|
89
|
+
buf.push_str("null");
|
|
90
|
+
}
|
|
89
91
|
#[cfg(feature = "regex")]
|
|
90
92
|
Value::RegExp(_) => buf.push_str("null"),
|
|
91
93
|
}
|
|
@@ -312,7 +314,10 @@ fn parse_object(input: &str) -> Result<(Value, &str), String> {
|
|
|
312
314
|
|
|
313
315
|
input = input.trim_start();
|
|
314
316
|
if let Some(rest) = input.strip_prefix('}') {
|
|
315
|
-
return Ok((
|
|
317
|
+
return Ok((
|
|
318
|
+
Value::Object(VmRef::new(crate::ObjectData::from_strings(map))),
|
|
319
|
+
rest,
|
|
320
|
+
));
|
|
316
321
|
}
|
|
317
322
|
|
|
318
323
|
loop {
|
|
@@ -339,7 +344,12 @@ fn parse_object(input: &str) -> Result<(Value, &str), String> {
|
|
|
339
344
|
|
|
340
345
|
match input.chars().next() {
|
|
341
346
|
Some(',') => input = &input[1..],
|
|
342
|
-
Some('}') =>
|
|
347
|
+
Some('}') => {
|
|
348
|
+
return Ok((
|
|
349
|
+
Value::Object(VmRef::new(crate::ObjectData::from_strings(map))),
|
|
350
|
+
&input[1..],
|
|
351
|
+
));
|
|
352
|
+
}
|
|
343
353
|
_ => return Err("Expected ',' or '}' in object".to_string()),
|
|
344
354
|
}
|
|
345
355
|
}
|
|
@@ -369,7 +379,7 @@ mod tests {
|
|
|
369
379
|
|
|
370
380
|
match (&value, &reparsed) {
|
|
371
381
|
(Value::Object(a), Value::Object(b)) => {
|
|
372
|
-
assert_eq!(a.borrow().
|
|
382
|
+
assert_eq!(a.borrow().len_entries(), b.borrow().len_entries());
|
|
373
383
|
}
|
|
374
384
|
_ => panic!("Expected objects"),
|
|
375
385
|
}
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
macro_rules! tish_module {
|
|
25
25
|
($($name:expr => $fn:expr),* $(,)?) => {{
|
|
26
26
|
use std::sync::Arc;
|
|
27
|
-
use $crate::{ObjectMap, Value
|
|
27
|
+
use $crate::{ObjectMap, Value};
|
|
28
28
|
let mut map = ObjectMap::default();
|
|
29
29
|
$(
|
|
30
30
|
// `Value::native` picks the right Rc / Arc wrapper depending on
|
|
31
31
|
// whether the `send-values` feature is enabled upstream.
|
|
32
32
|
map.insert(Arc::from($name), Value::native($fn));
|
|
33
33
|
)*
|
|
34
|
-
Value::
|
|
34
|
+
Value::object(map)
|
|
35
35
|
}};
|
|
36
36
|
}
|