@tishlang/tish 1.9.2 → 1.10.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/main.rs +11 -8
- 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 +43 -15
- 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/object.rs +10 -10
- package/crates/tish_builtins/src/string.rs +1 -3
- package/crates/tish_builtins/src/symbol.rs +83 -0
- package/crates/tish_compile/src/codegen.rs +123 -138
- package/crates/tish_compile/src/lib.rs +25 -3
- package/crates/tish_compile/src/resolve.rs +6 -3
- 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 +192 -4
- 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 +187 -10
- package/crates/tish_native/src/lib.rs +92 -8
- 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 +26 -43
- 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/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 +2 -2
- package/crates/tish_ui/src/runtime/hooks.rs +5 -15
- package/crates/tish_ui/src/runtime/mod.rs +16 -17
- package/crates/tish_vm/Cargo.toml +2 -0
- package/crates/tish_vm/src/vm.rs +218 -153
- package/crates/tish_wasm/src/lib.rs +33 -7
- package/crates/tish_wasm_runtime/Cargo.toml +4 -1
- package/crates/tish_wasm_runtime/src/lib.rs +2 -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
package/bin/tish
CHANGED
|
Binary file
|
|
@@ -539,9 +539,10 @@ pub fn convert_params(
|
|
|
539
539
|
let fp = p;
|
|
540
540
|
{
|
|
541
541
|
let (name, name_span) = match &fp.pattern {
|
|
542
|
-
oxc::ast::ast::BindingPattern::BindingIdentifier(b) =>
|
|
543
|
-
|
|
544
|
-
|
|
542
|
+
oxc::ast::ast::BindingPattern::BindingIdentifier(b) => (
|
|
543
|
+
b.name.as_str(),
|
|
544
|
+
crate::span_util::oxc_span_to_tish(ctx.1, b.as_ref()),
|
|
545
|
+
),
|
|
545
546
|
_ => {
|
|
546
547
|
return Err(ConvertError::new(ConvertErrorKind::Unsupported {
|
|
547
548
|
what: "destructuring in params".into(),
|
|
@@ -565,9 +566,10 @@ pub fn convert_params(
|
|
|
565
566
|
if rest_param.is_none() {
|
|
566
567
|
if let Some(rest) = ¶ms.rest {
|
|
567
568
|
let (rest_name, rest_name_span) = match &rest.rest.argument {
|
|
568
|
-
oxc::ast::ast::BindingPattern::BindingIdentifier(b) =>
|
|
569
|
-
|
|
570
|
-
|
|
569
|
+
oxc::ast::ast::BindingPattern::BindingIdentifier(b) => (
|
|
570
|
+
b.name.as_str(),
|
|
571
|
+
crate::span_util::oxc_span_to_tish(ctx.1, b.as_ref()),
|
|
572
|
+
),
|
|
571
573
|
_ => {
|
|
572
574
|
return Err(ConvertError::new(ConvertErrorKind::Unsupported {
|
|
573
575
|
what: "rest param with non-identifier".into(),
|
|
@@ -247,9 +247,10 @@ fn convert_for_of_statement(
|
|
|
247
247
|
if v.declarations.len() == 1 {
|
|
248
248
|
let d = &v.declarations[0];
|
|
249
249
|
match &d.id {
|
|
250
|
-
oxc::ast::ast::BindingPattern::BindingIdentifier(b) =>
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
oxc::ast::ast::BindingPattern::BindingIdentifier(b) => (
|
|
251
|
+
b.name.as_str(),
|
|
252
|
+
span_util::oxc_span_to_tish(ctx.1, b.as_ref()),
|
|
253
|
+
),
|
|
253
254
|
_ => {
|
|
254
255
|
return Err(ConvertError::new(ConvertErrorKind::Incompatible {
|
|
255
256
|
what: "for-of with destructuring".into(),
|
|
@@ -368,16 +369,14 @@ fn convert_function_decl(
|
|
|
368
369
|
span: Span,
|
|
369
370
|
) -> Result<Statement, ConvertError> {
|
|
370
371
|
let async_ = f.r#async;
|
|
371
|
-
let name: Arc<str> =
|
|
372
|
-
.id
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
.map(|id| span_util::oxc_span_to_tish(ctx.1, id))
|
|
380
|
-
.unwrap_or_else(span_util::stub_span);
|
|
372
|
+
let name: Arc<str> =
|
|
373
|
+
f.id.as_ref()
|
|
374
|
+
.map(|id| Arc::from(id.name.as_str()))
|
|
375
|
+
.unwrap_or_else(|| Arc::from(""));
|
|
376
|
+
let name_span =
|
|
377
|
+
f.id.as_ref()
|
|
378
|
+
.map(|id| span_util::oxc_span_to_tish(ctx.1, id))
|
|
379
|
+
.unwrap_or_else(span_util::stub_span);
|
|
381
380
|
let (params, rest_param) = expr::convert_params(&f.params, ctx)?;
|
|
382
381
|
let body = match &f.body {
|
|
383
382
|
Some(fb) => {
|
package/crates/tish/Cargo.toml
CHANGED
|
@@ -19,7 +19,10 @@ pub(crate) fn register_bytecode_native_modules(vm: &mut tishlang_vm::Vm) {
|
|
|
19
19
|
Arc::from("query_prepared"),
|
|
20
20
|
Value::native(tishlang_pg::query_prepared),
|
|
21
21
|
);
|
|
22
|
-
om.insert(
|
|
22
|
+
om.insert(
|
|
23
|
+
Arc::from("query_all"),
|
|
24
|
+
Value::native(tishlang_pg::query_all),
|
|
25
|
+
);
|
|
23
26
|
om.insert(Arc::from("migrate"), Value::native(tishlang_pg::migrate));
|
|
24
27
|
om.insert(Arc::from("close"), Value::native(tishlang_pg::close));
|
|
25
28
|
vm.register_native_module("cargo:tish_pg", om);
|
package/crates/tish/src/main.rs
CHANGED
|
@@ -4,13 +4,11 @@ mod cargo_native_registry;
|
|
|
4
4
|
mod cli_help;
|
|
5
5
|
mod repl_completion;
|
|
6
6
|
|
|
7
|
-
use std::cell::RefCell;
|
|
8
|
-
use tishlang_core::VmRef;
|
|
9
7
|
use std::collections::HashSet;
|
|
10
8
|
use std::fs;
|
|
11
9
|
use std::io::{self, IsTerminal, Read, Write};
|
|
12
10
|
use std::path::{Path, PathBuf};
|
|
13
|
-
use
|
|
11
|
+
use tishlang_core::VmRef;
|
|
14
12
|
|
|
15
13
|
use clap::FromArgMatches;
|
|
16
14
|
use rustyline::{Behavior, ColorMode, CompletionType, Config, Editor};
|
|
@@ -516,13 +514,14 @@ fn compile_to_js(
|
|
|
516
514
|
} else {
|
|
517
515
|
program
|
|
518
516
|
};
|
|
519
|
-
let js =
|
|
517
|
+
let js =
|
|
518
|
+
tishlang_compile_js::compile_with_jsx(&p, optimize).map_err(|e| format!("{}", e))?;
|
|
520
519
|
(js, None)
|
|
521
520
|
} else if input_path.extension().map(|e| e == "js") == Some(true) {
|
|
522
521
|
let source = fs::read_to_string(input_path).map_err(|e| format!("{}", e))?;
|
|
523
522
|
let program = tishlang_js_to_tish::convert(&source).map_err(|e| format!("{}", e))?;
|
|
524
|
-
let js =
|
|
525
|
-
|
|
523
|
+
let js = tishlang_compile_js::compile_with_jsx(&program, optimize)
|
|
524
|
+
.map_err(|e| format!("{}", e))?;
|
|
526
525
|
(js, None)
|
|
527
526
|
} else if source_map {
|
|
528
527
|
let bundle = tishlang_compile_js::compile_project_with_jsx_and_source_map(
|
|
@@ -545,7 +544,8 @@ fn compile_to_js(
|
|
|
545
544
|
let mut js_out = js;
|
|
546
545
|
if let Some(map) = &map_json {
|
|
547
546
|
let map_path = out_path.with_extension("js.map");
|
|
548
|
-
fs::write(&map_path, map)
|
|
547
|
+
fs::write(&map_path, map)
|
|
548
|
+
.map_err(|e| format!("Cannot write {}: {}", map_path.display(), e))?;
|
|
549
549
|
let map_url = map_path
|
|
550
550
|
.file_name()
|
|
551
551
|
.and_then(|s| s.to_str())
|
|
@@ -553,7 +553,8 @@ fn compile_to_js(
|
|
|
553
553
|
js_out.push_str(&format!("\n//# sourceMappingURL={map_url}\n"));
|
|
554
554
|
println!("Built: {}", map_path.display());
|
|
555
555
|
}
|
|
556
|
-
fs::write(&out_path, js_out)
|
|
556
|
+
fs::write(&out_path, js_out)
|
|
557
|
+
.map_err(|e| format!("Cannot write {}: {}", out_path.display(), e))?;
|
|
557
558
|
println!("Built: {}", out_path.display());
|
|
558
559
|
Ok(())
|
|
559
560
|
}
|
|
@@ -611,11 +612,13 @@ fn build_file(
|
|
|
611
612
|
Some(p)
|
|
612
613
|
}
|
|
613
614
|
});
|
|
615
|
+
let features = native_build_features_from_cli(cli_features);
|
|
614
616
|
return tishlang_wasm::compile_to_wasi(
|
|
615
617
|
&input_path,
|
|
616
618
|
project_root,
|
|
617
619
|
Path::new(output_path),
|
|
618
620
|
optimize,
|
|
621
|
+
&features,
|
|
619
622
|
)
|
|
620
623
|
.map_err(|e| e.to_string());
|
|
621
624
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
//! - Generate/update expected files: `REGENERATE_EXPECTED=1 cargo test -p tishlangtest_mvp_programs_interpreter`
|
|
6
6
|
//! then commit the new/updated `tests/core/*.tish.expected` files.
|
|
7
7
|
//! - Compiled outputs are cached under `target/integration_compile_cache/` per backend.
|
|
8
|
+
//! MVP native tests use `native_many/<hash>/` plus one batched nested Cargo build.
|
|
8
9
|
|
|
9
10
|
use std::collections::hash_map::DefaultHasher;
|
|
10
11
|
use std::ffi::OsString;
|
|
@@ -14,6 +15,7 @@ use std::path::{Path, PathBuf};
|
|
|
14
15
|
use std::process::Command;
|
|
15
16
|
|
|
16
17
|
use rayon::prelude::*;
|
|
18
|
+
use tishlang_native::compile_many_to_native;
|
|
17
19
|
|
|
18
20
|
fn workspace_root() -> PathBuf {
|
|
19
21
|
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
@@ -50,6 +52,72 @@ fn integration_compile_cache_dir() -> PathBuf {
|
|
|
50
52
|
target_dir().join("integration_compile_cache")
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
/// Match `tish build` with no `--feature`: link every capability compiled into this `tish` binary.
|
|
56
|
+
fn native_build_features_for_integration_test() -> Vec<String> {
|
|
57
|
+
let mut v: Vec<String> = tishlang_vm::all_compiled_capabilities()
|
|
58
|
+
.into_iter()
|
|
59
|
+
.collect();
|
|
60
|
+
v.sort();
|
|
61
|
+
v
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fn combined_mvp_native_inputs_hash(paths: &[PathBuf]) -> u64 {
|
|
65
|
+
let mut h = DefaultHasher::new();
|
|
66
|
+
let feats = native_build_features_for_integration_test();
|
|
67
|
+
feats.len().hash(&mut h);
|
|
68
|
+
for f in &feats {
|
|
69
|
+
f.hash(&mut h);
|
|
70
|
+
}
|
|
71
|
+
paths.len().hash(&mut h);
|
|
72
|
+
for p in paths {
|
|
73
|
+
p.file_name()
|
|
74
|
+
.unwrap_or_default()
|
|
75
|
+
.to_string_lossy()
|
|
76
|
+
.hash(&mut h);
|
|
77
|
+
file_content_hash(p).hash(&mut h);
|
|
78
|
+
}
|
|
79
|
+
// Native batch cache must invalidate when the emitter or `value_call` changes — not only
|
|
80
|
+
// when `.tish` sources change; otherwise CI/rust-cache can keep stale nested binaries.
|
|
81
|
+
let codegen_rs = workspace_root().join("crates/tish_compile/src/codegen.rs");
|
|
82
|
+
if codegen_rs.is_file() {
|
|
83
|
+
file_content_hash(&codegen_rs).hash(&mut h);
|
|
84
|
+
}
|
|
85
|
+
let value_rs = workspace_root().join("crates/tish_core/src/value.rs");
|
|
86
|
+
if value_rs.is_file() {
|
|
87
|
+
file_content_hash(&value_rs).hash(&mut h);
|
|
88
|
+
}
|
|
89
|
+
h.finish()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fn mvp_native_batch_cache_dir(combined: u64) -> PathBuf {
|
|
93
|
+
integration_compile_cache_dir()
|
|
94
|
+
.join("native_many")
|
|
95
|
+
.join(format!("{:016x}", combined))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// Restores the previous process env when dropped (for `TISH_FAST_NATIVE_BUILD` in batch tests).
|
|
99
|
+
struct EnvVarGuard {
|
|
100
|
+
key: &'static str,
|
|
101
|
+
previous: Option<std::ffi::OsString>,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
impl EnvVarGuard {
|
|
105
|
+
fn set(key: &'static str, value: &str) -> Self {
|
|
106
|
+
let previous = std::env::var_os(key);
|
|
107
|
+
std::env::set_var(key, value);
|
|
108
|
+
Self { key, previous }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
impl Drop for EnvVarGuard {
|
|
113
|
+
fn drop(&mut self) {
|
|
114
|
+
match &self.previous {
|
|
115
|
+
None => std::env::remove_var(self.key),
|
|
116
|
+
Some(v) => std::env::set_var(self.key, v),
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
53
121
|
fn file_content_hash(path: &Path) -> u64 {
|
|
54
122
|
let mut f = std::fs::File::open(path).expect("open file for hash");
|
|
55
123
|
let mut content = Vec::new();
|
|
@@ -583,6 +651,7 @@ const MVP_TEST_FILES: &[&str] = &[
|
|
|
583
651
|
"break_continue.tish",
|
|
584
652
|
"length.tish",
|
|
585
653
|
"objects.tish",
|
|
654
|
+
"symbol.tish",
|
|
586
655
|
"conditional.tish",
|
|
587
656
|
"switch.tish",
|
|
588
657
|
"do_while.tish",
|
|
@@ -714,6 +783,7 @@ fn test_mvp_programs_interp_vm_stdout_parity() {
|
|
|
714
783
|
/// Compile each .tish file to native, run, and compare stdout to static expected (parallelized).
|
|
715
784
|
#[test]
|
|
716
785
|
fn test_mvp_programs_native() {
|
|
786
|
+
let _fast_native = EnvVarGuard::set("TISH_FAST_NATIVE_BUILD", "1");
|
|
717
787
|
let core_dir = core_dir();
|
|
718
788
|
let bin = tish_bin();
|
|
719
789
|
assert!(
|
|
@@ -721,18 +791,86 @@ fn test_mvp_programs_native() {
|
|
|
721
791
|
"tish binary not found at {}. Run `cargo build -p tishlang` first.",
|
|
722
792
|
bin.display()
|
|
723
793
|
);
|
|
724
|
-
|
|
725
|
-
|
|
794
|
+
|
|
795
|
+
let mut paths: Vec<PathBuf> = MVP_TEST_FILES
|
|
796
|
+
.iter()
|
|
726
797
|
.filter_map(|name| {
|
|
727
|
-
let
|
|
728
|
-
if
|
|
729
|
-
|
|
798
|
+
let p = core_dir.join(name);
|
|
799
|
+
if p.exists() {
|
|
800
|
+
Some(p)
|
|
801
|
+
} else {
|
|
802
|
+
None
|
|
730
803
|
}
|
|
731
|
-
|
|
804
|
+
})
|
|
805
|
+
.collect();
|
|
806
|
+
paths.sort();
|
|
807
|
+
|
|
808
|
+
if paths.is_empty() {
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
let combined = combined_mvp_native_inputs_hash(&paths);
|
|
813
|
+
let cache_dir = mvp_native_batch_cache_dir(combined);
|
|
814
|
+
let _ = std::fs::create_dir_all(&cache_dir);
|
|
815
|
+
|
|
816
|
+
let ext = if cfg!(target_os = "windows") {
|
|
817
|
+
".exe"
|
|
818
|
+
} else {
|
|
819
|
+
""
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
let entries_owned: Vec<(PathBuf, PathBuf)> = paths
|
|
823
|
+
.iter()
|
|
824
|
+
.map(|p| {
|
|
825
|
+
let stem = p.file_stem().unwrap().to_string_lossy();
|
|
826
|
+
let cached = cache_dir.join(format!("{}{}", stem, ext));
|
|
827
|
+
(p.clone(), cached)
|
|
828
|
+
})
|
|
829
|
+
.collect();
|
|
830
|
+
|
|
831
|
+
let need_build = entries_owned.iter().any(|(_, o)| !o.exists());
|
|
832
|
+
if need_build {
|
|
833
|
+
let refs: Vec<(&Path, &Path)> = entries_owned
|
|
834
|
+
.iter()
|
|
835
|
+
.map(|(a, b)| (a.as_path(), b.as_path()))
|
|
836
|
+
.collect();
|
|
837
|
+
let feats = native_build_features_for_integration_test();
|
|
838
|
+
compile_many_to_native(&refs, Some(workspace_root().as_path()), &feats, true)
|
|
839
|
+
.unwrap_or_else(|e| panic!("compile_many_to_native: {}", e.message));
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Run each binary sequentially. Parallel `fs::copy` + `exec` caused Linux ETXTBSY (errno 26)
|
|
843
|
+
// in CI when several threads replaced/ran temp executables under load.
|
|
844
|
+
let errors: Vec<String> = entries_owned
|
|
845
|
+
.iter()
|
|
846
|
+
.enumerate()
|
|
847
|
+
.filter_map(|(run_index, (path, cached_bin))| {
|
|
848
|
+
let expected = match get_expected(path) {
|
|
732
849
|
Some(e) => e,
|
|
733
850
|
None => return Some(format!("missing expected: {}", path.display())),
|
|
734
851
|
};
|
|
735
|
-
|
|
852
|
+
if !cached_bin.exists() {
|
|
853
|
+
return Some(format!("missing cached binary: {}", cached_bin.display()));
|
|
854
|
+
}
|
|
855
|
+
let stem = path.file_stem().unwrap().to_string_lossy();
|
|
856
|
+
let ext_bin = cached_bin
|
|
857
|
+
.extension()
|
|
858
|
+
.map(|e| e.to_string_lossy().to_string())
|
|
859
|
+
.unwrap_or_default();
|
|
860
|
+
let temp_dest = std::env::temp_dir().join(format!(
|
|
861
|
+
"tish_mvp_native_{}_{:x}_{}_{}",
|
|
862
|
+
stem,
|
|
863
|
+
file_content_hash(path),
|
|
864
|
+
std::process::id(),
|
|
865
|
+
run_index
|
|
866
|
+
));
|
|
867
|
+
let temp_dest = if ext_bin.is_empty() {
|
|
868
|
+
temp_dest
|
|
869
|
+
} else {
|
|
870
|
+
temp_dest.with_extension(&ext_bin)
|
|
871
|
+
};
|
|
872
|
+
std::fs::copy(cached_bin, &temp_dest).expect("copy cached native bin to temp");
|
|
873
|
+
let out_bin = temp_dest;
|
|
736
874
|
let out = match Command::new(&out_bin)
|
|
737
875
|
.current_dir(workspace_root())
|
|
738
876
|
.output()
|
|
@@ -129,15 +129,9 @@ pub enum ImportSpecifier {
|
|
|
129
129
|
alias_span: Option<Span>,
|
|
130
130
|
},
|
|
131
131
|
/// Namespace: * as M
|
|
132
|
-
Namespace {
|
|
133
|
-
name: Arc<str>,
|
|
134
|
-
name_span: Span,
|
|
135
|
-
},
|
|
132
|
+
Namespace { name: Arc<str>, name_span: Span },
|
|
136
133
|
/// Default: import X from "..."
|
|
137
|
-
Default {
|
|
138
|
-
name: Arc<str>,
|
|
139
|
-
name_span: Span,
|
|
140
|
-
},
|
|
134
|
+
Default { name: Arc<str>, name_span: Span },
|
|
141
135
|
}
|
|
142
136
|
|
|
143
137
|
/// Export declaration: named (const/let/fn) or default
|
|
@@ -616,7 +610,7 @@ impl Statement {
|
|
|
616
610
|
| Statement::DoWhile { span, .. }
|
|
617
611
|
| Statement::Throw { span, .. }
|
|
618
612
|
| Statement::Try { span, .. }
|
|
619
|
-
|
|
|
613
|
+
| Statement::Import { span, .. }
|
|
620
614
|
| Statement::Export { span, .. }
|
|
621
615
|
| Statement::TypeAlias { span, .. }
|
|
622
616
|
| Statement::DeclareVar { span, .. }
|
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
use std::fs;
|
|
7
7
|
use std::path::{Path, PathBuf};
|
|
8
8
|
use std::process::Command;
|
|
9
|
+
use std::sync::Mutex;
|
|
10
|
+
|
|
11
|
+
/// Serialize nested `cargo build` calls that share the workspace `target/` dir (tests + `tish build`).
|
|
12
|
+
static NESTED_CARGO_MUTEX: Mutex<()> = Mutex::new(());
|
|
13
|
+
|
|
14
|
+
fn mold_available() -> bool {
|
|
15
|
+
Command::new("mold")
|
|
16
|
+
.arg("--version")
|
|
17
|
+
.output()
|
|
18
|
+
.map(|o| o.status.success())
|
|
19
|
+
.unwrap_or(false)
|
|
20
|
+
}
|
|
9
21
|
|
|
10
22
|
/// True if `root` looks like the Tish language repo (has `crates/tish_runtime`).
|
|
11
23
|
///
|
|
@@ -161,7 +173,11 @@ pub fn find_workspace_root() -> Result<PathBuf, String> {
|
|
|
161
173
|
let candidate = dir.join("tish");
|
|
162
174
|
if is_tish_workspace_root(&candidate) {
|
|
163
175
|
return candidate.canonicalize().map_err(|e| {
|
|
164
|
-
format!(
|
|
176
|
+
format!(
|
|
177
|
+
"Cannot canonicalize Tish workspace {}: {}",
|
|
178
|
+
candidate.display(),
|
|
179
|
+
e
|
|
180
|
+
)
|
|
165
181
|
});
|
|
166
182
|
}
|
|
167
183
|
if !dir.pop() {
|
|
@@ -366,20 +382,31 @@ fn protoc_for_nested_cargo() -> Option<PathBuf> {
|
|
|
366
382
|
/// Run cargo build in the given directory.
|
|
367
383
|
/// If target_dir is Some, use that for --target-dir (e.g. workspace target for caching).
|
|
368
384
|
pub fn run_cargo_build(build_dir: &Path, target_dir: Option<&Path>) -> Result<(), String> {
|
|
385
|
+
let _nested_guard = NESTED_CARGO_MUTEX.lock().unwrap_or_else(|e| e.into_inner());
|
|
386
|
+
|
|
369
387
|
let target_dir = target_dir
|
|
370
388
|
.map(|p| p.to_path_buf())
|
|
371
389
|
.unwrap_or_else(|| build_dir.join("target"));
|
|
390
|
+
let fast_native = std::env::var("TISH_FAST_NATIVE_BUILD").as_deref() == Ok("1");
|
|
391
|
+
|
|
372
392
|
// Default to target-cpu=native so the emitted binary uses every SIMD / ISA
|
|
373
393
|
// extension the build host supports. Callers can override by pre-setting
|
|
374
|
-
// RUSTFLAGS in the environment.
|
|
375
|
-
let
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
394
|
+
// RUSTFLAGS in the environment. Skipped for fast nested builds (integration tests).
|
|
395
|
+
let mut merged_rustflags = std::env::var("RUSTFLAGS").unwrap_or_default();
|
|
396
|
+
if fast_native {
|
|
397
|
+
if cfg!(target_os = "linux")
|
|
398
|
+
&& mold_available()
|
|
399
|
+
&& !merged_rustflags.contains("fuse-ld=mold")
|
|
400
|
+
{
|
|
401
|
+
merged_rustflags = format!("{} -C link-arg=-fuse-ld=mold", merged_rustflags.trim());
|
|
402
|
+
merged_rustflags = merged_rustflags.trim().to_string();
|
|
403
|
+
}
|
|
404
|
+
} else if merged_rustflags.is_empty() {
|
|
405
|
+
merged_rustflags = "-C target-cpu=native".to_string();
|
|
406
|
+
} else if !merged_rustflags.contains("target-cpu") {
|
|
407
|
+
merged_rustflags = format!("{} -C target-cpu=native", merged_rustflags);
|
|
408
|
+
}
|
|
409
|
+
|
|
383
410
|
// Nested `cargo build` (e.g. `tish build --native-backend rust`) inherits the parent
|
|
384
411
|
// environment. CI often sets `RUSTC_WRAPPER=sccache`; wrapping this inner compile too can
|
|
385
412
|
// cause flaky or failed builds (LTO / temp-crate paths). Use plain rustc here; the main
|
|
@@ -394,6 +421,11 @@ pub fn run_cargo_build(build_dir: &Path, target_dir: Option<&Path>) -> Result<()
|
|
|
394
421
|
.env_remove("CARGO_BUILD_RUSTC_WRAPPER")
|
|
395
422
|
.env("CARGO_TERM_PROGRESS", "always")
|
|
396
423
|
.env("RUSTFLAGS", &merged_rustflags);
|
|
424
|
+
if fast_native {
|
|
425
|
+
cmd.env("CARGO_INCREMENTAL", "1");
|
|
426
|
+
} else {
|
|
427
|
+
cmd.env_remove("CARGO_INCREMENTAL");
|
|
428
|
+
}
|
|
397
429
|
if let Some(protoc) = protoc_for_nested_cargo() {
|
|
398
430
|
cmd.env("PROTOC", protoc);
|
|
399
431
|
}
|
|
@@ -422,11 +454,7 @@ mod protoc_tests {
|
|
|
422
454
|
let _guard = _lock.lock().unwrap();
|
|
423
455
|
std::env::remove_var("PROTOC");
|
|
424
456
|
let p = protoc_for_nested_cargo().expect("expected vendored or PATH protoc");
|
|
425
|
-
assert!(
|
|
426
|
-
p.exists(),
|
|
427
|
-
"resolved protoc should exist: {}",
|
|
428
|
-
p.display()
|
|
429
|
-
);
|
|
457
|
+
assert!(p.exists(), "resolved protoc should exist: {}", p.display());
|
|
430
458
|
}
|
|
431
459
|
}
|
|
432
460
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
//! Array builtin methods.
|
|
2
2
|
|
|
3
3
|
use crate::helpers::normalize_index;
|
|
4
|
-
use tishlang_core::VmRef;
|
|
5
|
-
use std::cell::RefCell;
|
|
6
|
-
use std::rc::Rc;
|
|
7
4
|
use tishlang_core::Value;
|
|
5
|
+
use tishlang_core::VmRef;
|
|
8
6
|
|
|
9
7
|
/// Create a new array Value from a Vec of Values.
|
|
10
8
|
pub fn from_vec(v: Vec<Value>) -> Value {
|
|
@@ -434,6 +432,7 @@ fn get_prop_number(v: &Value, prop: &std::sync::Arc<str>) -> f64 {
|
|
|
434
432
|
match v {
|
|
435
433
|
Value::Object(o) => o
|
|
436
434
|
.borrow()
|
|
435
|
+
.strings
|
|
437
436
|
.get(prop.as_ref())
|
|
438
437
|
.map(|v| v.as_number().unwrap_or(f64::NAN))
|
|
439
438
|
.unwrap_or(f64::NAN),
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
//! `new` lowering for non-JS targets: `construct(callee, args)` approximates JS `[[Construct]]`.
|
|
2
2
|
//! Browser-exact behavior remains on `tish build --target js`.
|
|
3
3
|
|
|
4
|
-
use std::cell::RefCell;
|
|
5
|
-
use tishlang_core::VmRef;
|
|
6
|
-
use std::rc::Rc;
|
|
7
4
|
use std::sync::Arc;
|
|
8
|
-
|
|
9
|
-
use tishlang_core::{ObjectMap, Value};
|
|
5
|
+
use tishlang_core::{ObjectMap, Value, VmRef};
|
|
10
6
|
|
|
11
7
|
const CONSTRUCT: &str = "__construct";
|
|
12
8
|
|
|
@@ -16,7 +12,7 @@ pub fn construct(callee: &Value, args: &[Value]) -> Value {
|
|
|
16
12
|
Value::Function(f) => f(args),
|
|
17
13
|
Value::Object(o) => {
|
|
18
14
|
let b = o.borrow();
|
|
19
|
-
if let Some(Value::Function(ctor)) = b.get(&Arc::from(CONSTRUCT)) {
|
|
15
|
+
if let Some(Value::Function(ctor)) = b.strings.get(&Arc::from(CONSTRUCT)) {
|
|
20
16
|
let c = ctor.clone();
|
|
21
17
|
drop(b);
|
|
22
18
|
return c(args);
|
|
@@ -30,7 +26,7 @@ pub fn construct(callee: &Value, args: &[Value]) -> Value {
|
|
|
30
26
|
fn param(initial: f64) -> Value {
|
|
31
27
|
let mut m = ObjectMap::default();
|
|
32
28
|
m.insert(Arc::from("value"), Value::Number(initial));
|
|
33
|
-
Value::
|
|
29
|
+
Value::object(m)
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
fn connect_fn() -> Value {
|
|
@@ -45,21 +41,21 @@ fn audio_node_stub() -> Value {
|
|
|
45
41
|
m.insert(Arc::from("frequency"), param(440.0));
|
|
46
42
|
m.insert(Arc::from("Q"), param(1.0));
|
|
47
43
|
m.insert(Arc::from("type"), Value::String("peaking".into()));
|
|
48
|
-
Value::
|
|
44
|
+
Value::object(m)
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
fn analyser_stub() -> Value {
|
|
52
48
|
let mut m = ObjectMap::default();
|
|
53
49
|
m.insert(Arc::from("connect"), connect_fn());
|
|
54
50
|
m.insert(Arc::from("fftSize"), Value::Number(2048.0));
|
|
55
|
-
Value::
|
|
51
|
+
Value::object(m)
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
fn stereo_panner_stub() -> Value {
|
|
59
55
|
let mut m = ObjectMap::default();
|
|
60
56
|
m.insert(Arc::from("connect"), connect_fn());
|
|
61
57
|
m.insert(Arc::from("pan"), param(0.0));
|
|
62
|
-
Value::
|
|
58
|
+
Value::object(m)
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
fn audio_buffer_stub(len: usize) -> Value {
|
|
@@ -71,7 +67,7 @@ fn audio_buffer_stub(len: usize) -> Value {
|
|
|
71
67
|
Arc::from("getChannelData"),
|
|
72
68
|
Value::native(move |_args| Value::Array(data2.clone())),
|
|
73
69
|
);
|
|
74
|
-
Value::
|
|
70
|
+
Value::object(m)
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
fn buffer_source_stub() -> Value {
|
|
@@ -79,12 +75,9 @@ fn buffer_source_stub() -> Value {
|
|
|
79
75
|
m.insert(Arc::from("buffer"), Value::Null);
|
|
80
76
|
m.insert(Arc::from("loop"), Value::Bool(false));
|
|
81
77
|
m.insert(Arc::from("connect"), connect_fn());
|
|
82
|
-
m.insert(
|
|
83
|
-
Arc::from("start"),
|
|
84
|
-
Value::native(|_| Value::Null),
|
|
85
|
-
);
|
|
78
|
+
m.insert(Arc::from("start"), Value::native(|_| Value::Null));
|
|
86
79
|
m.insert(Arc::from("stop"), Value::native(|_| Value::Null));
|
|
87
|
-
Value::
|
|
80
|
+
Value::object(m)
|
|
88
81
|
}
|
|
89
82
|
|
|
90
83
|
fn oscillator_stub() -> Value {
|
|
@@ -92,12 +85,9 @@ fn oscillator_stub() -> Value {
|
|
|
92
85
|
m.insert(Arc::from("frequency"), param(440.0));
|
|
93
86
|
m.insert(Arc::from("type"), Value::String("sine".into()));
|
|
94
87
|
m.insert(Arc::from("connect"), connect_fn());
|
|
95
|
-
m.insert(
|
|
96
|
-
Arc::from("start"),
|
|
97
|
-
Value::native(|_| Value::Null),
|
|
98
|
-
);
|
|
88
|
+
m.insert(Arc::from("start"), Value::native(|_| Value::Null));
|
|
99
89
|
m.insert(Arc::from("stop"), Value::native(|_| Value::Null));
|
|
100
|
-
Value::
|
|
90
|
+
Value::object(m)
|
|
101
91
|
}
|
|
102
92
|
|
|
103
93
|
fn audio_context_instance() -> Value {
|
|
@@ -140,12 +130,9 @@ fn audio_context_instance() -> Value {
|
|
|
140
130
|
Arc::from("createOscillator"),
|
|
141
131
|
Value::native(|_| oscillator_stub()),
|
|
142
132
|
);
|
|
143
|
-
ctx.insert(
|
|
144
|
-
Arc::from("decodeAudioData"),
|
|
145
|
-
Value::native(|_| Value::Null),
|
|
146
|
-
);
|
|
133
|
+
ctx.insert(Arc::from("decodeAudioData"), Value::native(|_| Value::Null));
|
|
147
134
|
|
|
148
|
-
Value::
|
|
135
|
+
Value::object(ctx)
|
|
149
136
|
}
|
|
150
137
|
|
|
151
138
|
/// Global `Uint8Array` for native/VM: `new Uint8Array(n)` → numeric array of zeros (not real bytes).
|
|
@@ -160,7 +147,7 @@ pub fn uint8_array_constructor_value() -> Value {
|
|
|
160
147
|
});
|
|
161
148
|
let mut m = ObjectMap::default();
|
|
162
149
|
m.insert(Arc::from(CONSTRUCT), ctor);
|
|
163
|
-
Value::
|
|
150
|
+
Value::object(m)
|
|
164
151
|
}
|
|
165
152
|
|
|
166
153
|
/// Global `AudioContext` for native/VM: stub graph (no real audio).
|
|
@@ -168,5 +155,5 @@ pub fn audio_context_constructor_value() -> Value {
|
|
|
168
155
|
let ctor = Value::native(|_args: &[Value]| audio_context_instance());
|
|
169
156
|
let mut m = ObjectMap::default();
|
|
170
157
|
m.insert(Arc::from(CONSTRUCT), ctor);
|
|
171
|
-
Value::
|
|
158
|
+
Value::object(m)
|
|
172
159
|
}
|