@tishlang/tish 1.0.13 → 1.0.14
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/crates/js_to_tish/Cargo.toml +4 -2
- package/crates/js_to_tish/src/span_util.rs +1 -1
- package/crates/js_to_tish/src/transform/expr.rs +15 -15
- package/crates/js_to_tish/src/transform/stmt.rs +7 -7
- package/crates/js_to_tish/src/transform.rs +1 -1
- package/crates/tish/Cargo.toml +22 -22
- package/crates/tish/src/main.rs +46 -46
- package/crates/tish/src/repl_completion.rs +4 -4
- package/crates/tish/tests/integration_test.rs +28 -28
- package/crates/tish_ast/Cargo.toml +3 -1
- package/crates/tish_ast/src/ast.rs +1 -1
- package/crates/tish_build_utils/Cargo.toml +3 -1
- package/crates/tish_build_utils/src/lib.rs +18 -6
- package/crates/tish_builtins/Cargo.toml +5 -3
- package/crates/tish_builtins/src/array.rs +2 -2
- package/crates/tish_builtins/src/globals.rs +3 -3
- package/crates/tish_builtins/src/helpers.rs +1 -1
- package/crates/tish_builtins/src/lib.rs +3 -3
- package/crates/tish_builtins/src/math.rs +1 -1
- package/crates/tish_builtins/src/object.rs +2 -2
- package/crates/tish_builtins/src/string.rs +1 -1
- package/crates/tish_bytecode/Cargo.toml +9 -7
- package/crates/tish_bytecode/src/chunk.rs +1 -1
- package/crates/tish_bytecode/src/compiler.rs +1 -1
- package/crates/tish_bytecode/src/encoding.rs +6 -6
- package/crates/tish_bytecode/tests/constant_folding.rs +7 -7
- package/crates/tish_bytecode/tests/shortcircuit.rs +11 -11
- package/crates/tish_bytecode/tests/sort_optimization.rs +3 -3
- package/crates/tish_compile/Cargo.toml +6 -4
- package/crates/tish_compile/src/codegen.rs +96 -96
- package/crates/tish_compile/src/lib.rs +2 -2
- package/crates/tish_compile/src/resolve.rs +7 -7
- package/crates/tish_compile/src/types.rs +1 -1
- package/crates/tish_compile_js/Cargo.toml +8 -6
- package/crates/tish_compile_js/src/codegen.rs +12 -12
- package/crates/tish_compile_js/src/js_intrinsics.rs +1 -1
- package/crates/tish_compile_js/src/lib.rs +2 -2
- package/crates/tish_compile_js/src/tests_jsx.rs +2 -2
- package/crates/tish_compiler_wasm/Cargo.toml +8 -6
- package/crates/tish_compiler_wasm/src/lib.rs +12 -12
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +3 -3
- package/crates/tish_core/Cargo.toml +3 -1
- package/crates/tish_core/src/lib.rs +1 -1
- package/crates/tish_core/src/macros.rs +1 -1
- package/crates/tish_core/src/value.rs +1 -1
- package/crates/tish_cranelift/Cargo.toml +6 -4
- package/crates/tish_cranelift/src/lib.rs +2 -2
- package/crates/tish_cranelift/src/link.rs +11 -11
- package/crates/tish_cranelift/src/lower.rs +3 -3
- package/crates/tish_cranelift_runtime/Cargo.toml +9 -7
- package/crates/tish_cranelift_runtime/src/lib.rs +2 -2
- package/crates/tish_eval/Cargo.toml +10 -8
- package/crates/tish_eval/src/eval.rs +35 -35
- package/crates/tish_eval/src/http.rs +1 -1
- package/crates/tish_eval/src/lib.rs +3 -3
- package/crates/tish_eval/src/natives.rs +2 -2
- package/crates/tish_eval/src/regex.rs +2 -2
- package/crates/tish_eval/src/value.rs +7 -7
- package/crates/tish_eval/src/value_convert.rs +3 -3
- package/crates/tish_fmt/Cargo.toml +3 -3
- package/crates/tish_fmt/src/bin/tish-fmt.rs +1 -1
- package/crates/tish_fmt/src/lib.rs +3 -3
- package/crates/tish_jsx_web/Cargo.toml +3 -1
- package/crates/tish_lexer/Cargo.toml +3 -1
- package/crates/tish_lint/Cargo.toml +3 -3
- package/crates/tish_lint/src/bin/tish-lint.rs +3 -3
- package/crates/tish_lint/src/lib.rs +15 -15
- package/crates/tish_llvm/Cargo.toml +7 -5
- package/crates/tish_llvm/src/lib.rs +10 -10
- package/crates/tish_lsp/Cargo.toml +5 -5
- package/crates/tish_lsp/src/main.rs +35 -35
- package/crates/tish_native/Cargo.toml +10 -8
- package/crates/tish_native/src/build.rs +8 -8
- package/crates/tish_native/src/lib.rs +39 -39
- package/crates/tish_opt/Cargo.toml +5 -3
- package/crates/tish_opt/src/lib.rs +27 -27
- package/crates/tish_parser/Cargo.toml +5 -3
- package/crates/tish_parser/src/lib.rs +4 -4
- package/crates/tish_parser/src/parser.rs +2 -2
- package/crates/tish_runtime/Cargo.toml +7 -5
- package/crates/tish_runtime/src/http.rs +1 -1
- package/crates/tish_runtime/src/http_fetch.rs +2 -2
- package/crates/tish_runtime/src/lib.rs +21 -21
- package/crates/tish_runtime/src/native_promise.rs +1 -1
- package/crates/tish_runtime/src/promise.rs +2 -2
- package/crates/tish_runtime/src/promise_io.rs +1 -1
- package/crates/tish_runtime/src/timers.rs +1 -1
- package/crates/tish_runtime/src/ws.rs +1 -1
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +2 -2
- package/crates/tish_vm/Cargo.toml +14 -12
- package/crates/tish_vm/src/lib.rs +2 -2
- package/crates/tish_vm/src/vm.rs +42 -42
- package/crates/tish_wasm/Cargo.toml +8 -6
- package/crates/tish_wasm/src/lib.rs +17 -17
- package/crates/tish_wasm_runtime/Cargo.toml +9 -7
- package/crates/tish_wasm_runtime/src/lib.rs +4 -4
- package/justfile +4 -4
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//! Native compiler backend for Tish.
|
|
2
2
|
//!
|
|
3
|
-
//! Emits Rust source that links to
|
|
3
|
+
//! Emits Rust source that links to tishlang_runtime.
|
|
4
4
|
|
|
5
5
|
mod codegen;
|
|
6
6
|
mod resolve;
|
|
@@ -21,7 +21,7 @@ pub use types::{RustType, TypeContext};
|
|
|
21
21
|
#[cfg(test)]
|
|
22
22
|
mod tests {
|
|
23
23
|
use super::*;
|
|
24
|
-
use
|
|
24
|
+
use tishlang_parser::parse;
|
|
25
25
|
|
|
26
26
|
#[test]
|
|
27
27
|
fn typed_assign_conversion() {
|
|
@@ -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
|
|
7
|
+
use tishlang_ast::{ExportDeclaration, Expr, ImportSpecifier, Program, Statement};
|
|
8
8
|
|
|
9
9
|
/// Resolved native module: crate path and init expression.
|
|
10
10
|
#[derive(Debug, Clone)]
|
|
@@ -37,14 +37,14 @@ pub fn normalize_builtin_spec(spec: &str) -> Option<String> {
|
|
|
37
37
|
.map(|(_, canonical)| (*canonical).to_string())
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/// Built-in modules that come from
|
|
40
|
+
/// Built-in modules that come from tishlang_runtime, not from package.json.
|
|
41
41
|
pub fn is_builtin_native_spec(spec: &str) -> bool {
|
|
42
42
|
matches!(spec, "tish:fs" | "tish:http" | "tish:process" | "tish:ws")
|
|
43
43
|
|| matches!(spec, "fs" | "http" | "process" | "ws")
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/// Resolve all native imports in a merged program via package.json lookup.
|
|
47
|
-
/// Built-in modules (tish:fs, tish:http, tish:process) are skipped - they use
|
|
47
|
+
/// Built-in modules (tish:fs, tish:http, tish:process) are skipped - they use tishlang_runtime directly.
|
|
48
48
|
pub fn resolve_native_modules(program: &Program, project_root: &Path) -> Result<Vec<ResolvedNativeModule>, String> {
|
|
49
49
|
let root_canon = project_root
|
|
50
50
|
.canonicalize()
|
|
@@ -59,7 +59,7 @@ pub fn resolve_native_modules(program: &Program, project_root: &Path) -> Result<
|
|
|
59
59
|
{
|
|
60
60
|
let s = spec.as_ref();
|
|
61
61
|
if is_builtin_native_spec(s) {
|
|
62
|
-
continue; // Built-ins use
|
|
62
|
+
continue; // Built-ins use tishlang_runtime, no package.json lookup
|
|
63
63
|
}
|
|
64
64
|
if !seen.insert(s.to_string()) {
|
|
65
65
|
continue;
|
|
@@ -152,7 +152,7 @@ fn read_package_name(pkg_path: &Path) -> Option<String> {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/// Extract Cargo feature names from native imports in a merged program.
|
|
155
|
-
/// Used to enable
|
|
155
|
+
/// Used to enable tishlang_runtime features based on `import { x } from 'tish:egui'` etc.
|
|
156
156
|
pub fn extract_native_import_features(program: &Program) -> Vec<String> {
|
|
157
157
|
let mut features = std::collections::HashSet::new();
|
|
158
158
|
for stmt in &program.statements {
|
|
@@ -260,7 +260,7 @@ fn load_module_recursive(
|
|
|
260
260
|
|
|
261
261
|
let source = std::fs::read_to_string(&canonical)
|
|
262
262
|
.map_err(|e| format!("Cannot read {}: {}", canonical.display(), e))?;
|
|
263
|
-
let program =
|
|
263
|
+
let program = tishlang_parser::parse(&source)
|
|
264
264
|
.map_err(|e| format!("Parse error in {}: {}", canonical.display(), e))?;
|
|
265
265
|
|
|
266
266
|
// Collect imports and load dependencies first (skip native imports)
|
|
@@ -568,7 +568,7 @@ pub fn merge_modules(modules: Vec<ResolvedModule>) -> Result<Program, String> {
|
|
|
568
568
|
ImportSpecifier::Namespace(ns) => {
|
|
569
569
|
let mut props = Vec::new();
|
|
570
570
|
for (k, v) in dep_exports {
|
|
571
|
-
props.push(
|
|
571
|
+
props.push(tishlang_ast::ObjectProp::KeyValue(
|
|
572
572
|
Arc::from(k.clone()),
|
|
573
573
|
Expr::Ident {
|
|
574
574
|
name: Arc::from(v.clone()),
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
2
|
+
name = "tishlang_compile_js"
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Tish to JavaScript transpiler backend"
|
|
6
6
|
|
|
7
|
+
license-file = { workspace = true }
|
|
8
|
+
repository = { workspace = true }
|
|
7
9
|
[features]
|
|
8
10
|
default = []
|
|
9
11
|
|
|
10
12
|
[dependencies]
|
|
11
|
-
|
|
13
|
+
tishlang_jsx_web = { path = "../tish_jsx_web" }
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
tishlang_ast = { path = "../tish_ast" }
|
|
16
|
+
tishlang_compile = { path = "../tish_compile" }
|
|
17
|
+
tishlang_opt = { path = "../tish_opt" }
|
|
18
|
+
tishlang_parser = { path = "../tish_parser" }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//! Code generation: AST -> JavaScript source.
|
|
2
2
|
|
|
3
|
-
use
|
|
3
|
+
use tishlang_ast::{
|
|
4
4
|
ArrayElement, ArrowBody, BinOp, CallArg, CompoundOp, DestructElement, DestructPattern, Expr,
|
|
5
5
|
JsxAttrValue, JsxChild, JsxProp, Literal, LogicalAssignOp, MemberProp, ObjectProp, Program,
|
|
6
6
|
Statement, UnaryOp,
|
|
@@ -71,7 +71,7 @@ impl Codegen {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
fn emit_program(&mut self, program: &Program) -> Result<(), CompileError> {
|
|
74
|
-
self.write("// Generated by
|
|
74
|
+
self.write("// Generated by tishlang_compile_js\n");
|
|
75
75
|
// First pass: check if JSX is used (we'll set uses_jsx during emit)
|
|
76
76
|
for stmt in &program.statements {
|
|
77
77
|
self.emit_statement(stmt)?;
|
|
@@ -84,7 +84,7 @@ impl Codegen {
|
|
|
84
84
|
JsxMode::Vdom => {
|
|
85
85
|
self.output = format!(
|
|
86
86
|
"{}\n{}",
|
|
87
|
-
|
|
87
|
+
tishlang_jsx_web::VDOM_PRELUDE,
|
|
88
88
|
self.output
|
|
89
89
|
);
|
|
90
90
|
}
|
|
@@ -331,8 +331,8 @@ impl Codegen {
|
|
|
331
331
|
|
|
332
332
|
fn emit_params(
|
|
333
333
|
&mut self,
|
|
334
|
-
params: &[
|
|
335
|
-
rest_param: Option<&
|
|
334
|
+
params: &[tishlang_ast::TypedParam],
|
|
335
|
+
rest_param: Option<&tishlang_ast::TypedParam>,
|
|
336
336
|
) -> Result<String, CompileError> {
|
|
337
337
|
let mut parts: Vec<String> = params
|
|
338
338
|
.iter()
|
|
@@ -745,7 +745,7 @@ pub fn compile_with_jsx(
|
|
|
745
745
|
jsx_mode: JsxMode,
|
|
746
746
|
) -> Result<String, CompileError> {
|
|
747
747
|
let program = if optimize {
|
|
748
|
-
|
|
748
|
+
tishlang_opt::optimize(program)
|
|
749
749
|
} else {
|
|
750
750
|
program.clone()
|
|
751
751
|
};
|
|
@@ -755,21 +755,21 @@ pub fn compile_with_jsx(
|
|
|
755
755
|
}
|
|
756
756
|
|
|
757
757
|
/// Compile a project from entry path, resolving and merging modules.
|
|
758
|
-
/// Uses shared resolve from
|
|
758
|
+
/// Uses shared resolve from tishlang_compile (same pipeline as native/WASM).
|
|
759
759
|
pub fn compile_project_with_jsx(
|
|
760
760
|
entry_path: &std::path::Path,
|
|
761
761
|
project_root: Option<&std::path::Path>,
|
|
762
762
|
optimize: bool,
|
|
763
763
|
jsx_mode: JsxMode,
|
|
764
764
|
) -> Result<String, CompileError> {
|
|
765
|
-
use
|
|
766
|
-
let modules =
|
|
765
|
+
use tishlang_ast::Statement;
|
|
766
|
+
let modules = tishlang_compile::resolve_project(entry_path, project_root)
|
|
767
767
|
.map_err(|e| CompileError { message: e })?;
|
|
768
|
-
|
|
768
|
+
tishlang_compile::detect_cycles(&modules).map_err(|e| CompileError { message: e })?;
|
|
769
769
|
let program = {
|
|
770
|
-
let prog =
|
|
770
|
+
let prog = tishlang_compile::merge_modules(modules).map_err(|e| CompileError { message: e })?;
|
|
771
771
|
if optimize {
|
|
772
|
-
|
|
772
|
+
tishlang_opt::optimize(&prog)
|
|
773
773
|
} else {
|
|
774
774
|
prog
|
|
775
775
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//! JS-only call sites that require `new` (Tish has no `new`).
|
|
2
2
|
//! Intrinsic names, validation, and runtime preamble live here — main codegen only dispatches.
|
|
3
3
|
|
|
4
|
-
use
|
|
4
|
+
use tishlang_ast::{CallArg, Expr};
|
|
5
5
|
|
|
6
6
|
use crate::error::CompileError;
|
|
7
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//! Tish to JavaScript transpiler backend.
|
|
2
|
-
//! Uses shared resolve from
|
|
2
|
+
//! Uses shared resolve from tishlang_compile for unified pipeline.
|
|
3
3
|
|
|
4
4
|
mod codegen;
|
|
5
5
|
mod error;
|
|
@@ -14,7 +14,7 @@ pub use error::CompileError;
|
|
|
14
14
|
/// Default JSX mode lowers to Lattish-style calls (implementation detail). Import what you use from
|
|
15
15
|
/// `lattish` (e.g. `useState`, `createRoot`); the merged bundle includes the JSX runtime from that
|
|
16
16
|
/// module. JSX-only files can use `import {} from "lattish"` to pull it in without bindings.
|
|
17
|
-
pub fn compile(program: &
|
|
17
|
+
pub fn compile(program: &tishlang_ast::Program, optimize: bool) -> Result<String, CompileError> {
|
|
18
18
|
compile_with_jsx(program, optimize, JsxMode::LattishH)
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mod tests {
|
|
3
3
|
use std::io::Write;
|
|
4
4
|
|
|
5
|
-
use
|
|
5
|
+
use tishlang_parser::parse;
|
|
6
6
|
|
|
7
7
|
use crate::{compile_project_with_jsx, compile_with_jsx, JsxMode};
|
|
8
8
|
|
|
@@ -53,7 +53,7 @@ mod tests {
|
|
|
53
53
|
|
|
54
54
|
#[test]
|
|
55
55
|
fn jsx_text_whitespace_via_compile_project() {
|
|
56
|
-
let dir = std::env::temp_dir().join("
|
|
56
|
+
let dir = std::env::temp_dir().join("tishlang_compile_project_test");
|
|
57
57
|
let _ = std::fs::create_dir_all(&dir);
|
|
58
58
|
let path = dir.join("test.tish");
|
|
59
59
|
let src = "fn App() {\n return <p>First paragraph</p>\n}";
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
2
|
+
name = "tishlang_compiler_wasm"
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Tish compiler as WASM for browser (parse + bytecode + JS)"
|
|
6
|
+
license-file = { workspace = true }
|
|
7
|
+
repository = { workspace = true }
|
|
6
8
|
|
|
7
9
|
[lib]
|
|
8
10
|
crate-type = ["cdylib"]
|
|
@@ -12,8 +14,8 @@ base64 = "0.22"
|
|
|
12
14
|
serde_json = "1.0"
|
|
13
15
|
wasm-bindgen = "0.2"
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
tishlang_ast = { path = "../tish_ast" }
|
|
18
|
+
tishlang_bytecode = { path = "../tish_bytecode" }
|
|
19
|
+
tishlang_compile_js = { path = "../tish_compile_js" }
|
|
20
|
+
tishlang_opt = { path = "../tish_opt" }
|
|
21
|
+
tishlang_parser = { path = "../tish_parser" }
|
|
@@ -10,21 +10,21 @@ mod resolve_virtual;
|
|
|
10
10
|
use base64::Engine;
|
|
11
11
|
use resolve_virtual::{detect_cycles_virtual, merge_modules_virtual, resolve_virtual};
|
|
12
12
|
use std::collections::HashMap;
|
|
13
|
-
use
|
|
13
|
+
use tishlang_compile_js::JsxMode;
|
|
14
14
|
use wasm_bindgen::prelude::*;
|
|
15
15
|
|
|
16
16
|
#[wasm_bindgen]
|
|
17
17
|
pub fn compile_to_bytecode(source: &str) -> Result<String, JsValue> {
|
|
18
|
-
let program =
|
|
19
|
-
let program =
|
|
20
|
-
let chunk =
|
|
21
|
-
Ok(base64::engine::general_purpose::STANDARD.encode(
|
|
18
|
+
let program = tishlang_parser::parse(source.trim()).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
19
|
+
let program = tishlang_opt::optimize(&program);
|
|
20
|
+
let chunk = tishlang_bytecode::compile(&program).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
21
|
+
Ok(base64::engine::general_purpose::STANDARD.encode(tishlang_bytecode::serialize(&chunk)))
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
#[wasm_bindgen]
|
|
25
25
|
pub fn compile_to_js(source: &str) -> Result<String, JsValue> {
|
|
26
|
-
let program =
|
|
27
|
-
|
|
26
|
+
let program = tishlang_parser::parse(source.trim()).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
27
|
+
tishlang_compile_js::compile_with_jsx(&program, true, JsxMode::LattishH)
|
|
28
28
|
.map_err(|e| JsValue::from_str(&e.message))
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -36,9 +36,9 @@ pub fn compile_to_bytecode_with_imports(entry_path: &str, files_json: &str) -> R
|
|
|
36
36
|
.map_err(|e| JsValue::from_str(&e))?;
|
|
37
37
|
detect_cycles_virtual(&modules).map_err(|e| JsValue::from_str(&e))?;
|
|
38
38
|
let program = merge_modules_virtual(modules).map_err(|e| JsValue::from_str(&e))?;
|
|
39
|
-
let program =
|
|
40
|
-
let chunk =
|
|
41
|
-
Ok(base64::engine::general_purpose::STANDARD.encode(
|
|
39
|
+
let program = tishlang_opt::optimize(&program);
|
|
40
|
+
let chunk = tishlang_bytecode::compile(&program).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
41
|
+
Ok(base64::engine::general_purpose::STANDARD.encode(tishlang_bytecode::serialize(&chunk)))
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
#[wasm_bindgen]
|
|
@@ -49,7 +49,7 @@ pub fn compile_to_js_with_imports(entry_path: &str, files_json: &str) -> Result<
|
|
|
49
49
|
.map_err(|e| JsValue::from_str(&e))?;
|
|
50
50
|
detect_cycles_virtual(&modules).map_err(|e| JsValue::from_str(&e))?;
|
|
51
51
|
let program = merge_modules_virtual(modules).map_err(|e| JsValue::from_str(&e))?;
|
|
52
|
-
let program =
|
|
53
|
-
|
|
52
|
+
let program = tishlang_opt::optimize(&program);
|
|
53
|
+
tishlang_compile_js::compile_with_jsx(&program, true, JsxMode::LattishH)
|
|
54
54
|
.map_err(|e| JsValue::from_str(&e.message))
|
|
55
55
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
use std::collections::{HashMap, HashSet};
|
|
5
5
|
use std::sync::Arc;
|
|
6
6
|
|
|
7
|
-
use
|
|
7
|
+
use tishlang_ast::{ExportDeclaration, Expr, ImportSpecifier, Program, Statement};
|
|
8
8
|
|
|
9
9
|
/// A resolved module: virtual path and its parsed program.
|
|
10
10
|
#[derive(Debug, Clone)]
|
|
@@ -150,7 +150,7 @@ fn load_module_recursive(
|
|
|
150
150
|
let source = files.get(module_path).ok_or_else(|| {
|
|
151
151
|
format!("Module '{}' not in virtual file map", module_path)
|
|
152
152
|
})?;
|
|
153
|
-
let program =
|
|
153
|
+
let program = tishlang_parser::parse(source.trim())
|
|
154
154
|
.map_err(|e| format!("Parse error in {}: {}", module_path, e))?;
|
|
155
155
|
|
|
156
156
|
let from_dir = parent_dir(module_path);
|
|
@@ -374,7 +374,7 @@ pub fn merge_modules_virtual(modules: Vec<VirtualModule>) -> Result<Program, Str
|
|
|
374
374
|
ImportSpecifier::Namespace(ns) => {
|
|
375
375
|
let mut props = Vec::new();
|
|
376
376
|
for (k, v) in dep_exports {
|
|
377
|
-
props.push(
|
|
377
|
+
props.push(tishlang_ast::ObjectProp::KeyValue(
|
|
378
378
|
Arc::from(k.clone()),
|
|
379
379
|
Expr::Ident {
|
|
380
380
|
name: Arc::from(v.clone()),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//! Tish Core - Shared types and utilities for the Tish language.
|
|
2
2
|
//!
|
|
3
3
|
//! This crate provides the unified Value type and utilities used by both
|
|
4
|
-
//! the interpreter (
|
|
4
|
+
//! the interpreter (tishlang_eval) and compiled runtime (tishlang_runtime).
|
|
5
5
|
|
|
6
6
|
mod console_style;
|
|
7
7
|
mod json;
|
|
@@ -151,7 +151,7 @@ pub enum Value {
|
|
|
151
151
|
Function(NativeFn),
|
|
152
152
|
#[cfg(feature = "regex")]
|
|
153
153
|
RegExp(Rc<RefCell<TishRegExp>>),
|
|
154
|
-
/// Promise (for native compile). Interpreter uses
|
|
154
|
+
/// Promise (for native compile). Interpreter uses tishlang_eval::Value::Promise.
|
|
155
155
|
Promise(Arc<dyn TishPromise>),
|
|
156
156
|
/// Opaque handle to a native Rust type (e.g. Polars DataFrame).
|
|
157
157
|
Opaque(Arc<dyn TishOpaque>),
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
2
|
+
name = "tishlang_cranelift"
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Bytecode to native via Cranelift"
|
|
6
6
|
|
|
7
|
+
license-file = { workspace = true }
|
|
8
|
+
repository = { workspace = true }
|
|
7
9
|
[dependencies]
|
|
8
|
-
|
|
10
|
+
tishlang_build_utils = { path = "../tish_build_utils" }
|
|
9
11
|
cranelift = "0.130"
|
|
10
12
|
cranelift-codegen = "0.130"
|
|
11
13
|
cranelift-frontend = "0.130"
|
|
@@ -13,5 +15,5 @@ cranelift-module = "0.130"
|
|
|
13
15
|
cranelift-native = "0.130"
|
|
14
16
|
cranelift-object = "0.130"
|
|
15
17
|
target-lexicon = "0.13"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
tishlang_bytecode = { path = "../tish_bytecode" }
|
|
19
|
+
tishlang_core = { path = "../tish_core" }
|
|
@@ -9,7 +9,7 @@ pub use link::link_to_binary;
|
|
|
9
9
|
|
|
10
10
|
use std::path::Path;
|
|
11
11
|
|
|
12
|
-
use
|
|
12
|
+
use tishlang_bytecode::Chunk;
|
|
13
13
|
|
|
14
14
|
/// Error from Cranelift compilation.
|
|
15
15
|
#[derive(Debug)]
|
|
@@ -26,7 +26,7 @@ impl std::fmt::Display for CraneliftError {
|
|
|
26
26
|
impl std::error::Error for CraneliftError {}
|
|
27
27
|
|
|
28
28
|
/// Compile a bytecode chunk to a native binary.
|
|
29
|
-
/// `features` are passed to
|
|
29
|
+
/// `features` are passed to tishlang_cranelift_runtime (e.g. fs, process, http for built-in modules).
|
|
30
30
|
pub fn compile_chunk_to_native(
|
|
31
31
|
chunk: &Chunk,
|
|
32
32
|
output_path: &Path,
|
|
@@ -12,14 +12,14 @@ pub fn link_to_binary(
|
|
|
12
12
|
output_path: &Path,
|
|
13
13
|
features: &[String],
|
|
14
14
|
) -> Result<(), CraneliftError> {
|
|
15
|
-
let workspace_root =
|
|
15
|
+
let workspace_root = tishlang_build_utils::find_workspace_root().map_err(|e| CraneliftError {
|
|
16
16
|
message: e,
|
|
17
17
|
})?;
|
|
18
18
|
let out_name = output_path
|
|
19
19
|
.file_stem()
|
|
20
20
|
.and_then(|s| s.to_str())
|
|
21
21
|
.unwrap_or("tish_out");
|
|
22
|
-
let build_dir =
|
|
22
|
+
let build_dir = tishlang_build_utils::create_build_dir("tishlang_cranelift_build", out_name)
|
|
23
23
|
.map_err(|e| CraneliftError { message: e })?;
|
|
24
24
|
|
|
25
25
|
let object_path_str = object_path
|
|
@@ -31,13 +31,13 @@ pub fn link_to_binary(
|
|
|
31
31
|
.to_string()
|
|
32
32
|
.replace('\\', "/");
|
|
33
33
|
|
|
34
|
-
//
|
|
34
|
+
// tishlang_cranelift_runtime crate lives in crates/tish_cranelift_runtime
|
|
35
35
|
let runtime_path = workspace_root
|
|
36
36
|
.join("crates")
|
|
37
37
|
.join("tish_cranelift_runtime")
|
|
38
38
|
.canonicalize()
|
|
39
39
|
.map_err(|e| CraneliftError {
|
|
40
|
-
message: format!("Cannot find
|
|
40
|
+
message: format!("Cannot find tishlang_cranelift_runtime: {}", e),
|
|
41
41
|
})?
|
|
42
42
|
.display()
|
|
43
43
|
.to_string()
|
|
@@ -57,7 +57,7 @@ pub fn link_to_binary(
|
|
|
57
57
|
};
|
|
58
58
|
let cargo_toml_fixed = format!(
|
|
59
59
|
r#"[package]
|
|
60
|
-
name = "
|
|
60
|
+
name = "tishlang_cranelift_out"
|
|
61
61
|
version = "0.1.0"
|
|
62
62
|
edition = "2021"
|
|
63
63
|
|
|
@@ -66,7 +66,7 @@ name = "{}"
|
|
|
66
66
|
path = "src/main.rs"
|
|
67
67
|
|
|
68
68
|
[dependencies]
|
|
69
|
-
|
|
69
|
+
tishlang_cranelift_runtime = {{ path = {:?}{} }}
|
|
70
70
|
"#,
|
|
71
71
|
out_name, runtime_path, features_str
|
|
72
72
|
);
|
|
@@ -80,7 +80,7 @@ extern "C" {
|
|
|
80
80
|
fn main() {
|
|
81
81
|
let len = unsafe { tish_chunk_len } as usize;
|
|
82
82
|
let ptr = unsafe { tish_chunk_data.as_ptr() };
|
|
83
|
-
let exit_code =
|
|
83
|
+
let exit_code = tishlang_cranelift_runtime::tish_run_chunk(ptr, len);
|
|
84
84
|
std::process::exit(exit_code);
|
|
85
85
|
}
|
|
86
86
|
"#;
|
|
@@ -104,14 +104,14 @@ fn main() {{
|
|
|
104
104
|
message: format!("Cannot write build.rs: {}", e),
|
|
105
105
|
})?;
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
tishlang_build_utils::run_cargo_build(&build_dir, None).map_err(|e| CraneliftError { message: e })?;
|
|
108
108
|
|
|
109
109
|
let binary_dir = build_dir.join("target").join("release");
|
|
110
110
|
let binary =
|
|
111
|
-
|
|
111
|
+
tishlang_build_utils::find_release_binary(&binary_dir, out_name)
|
|
112
112
|
.map_err(|e| CraneliftError { message: e })?;
|
|
113
|
-
let target =
|
|
114
|
-
|
|
113
|
+
let target = tishlang_build_utils::resolve_output_path(output_path, out_name);
|
|
114
|
+
tishlang_build_utils::copy_binary_to_output(&binary, &target)
|
|
115
115
|
.map_err(|e| CraneliftError { message: e })?;
|
|
116
116
|
|
|
117
117
|
Ok(())
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//! Bytecode to Cranelift IR lowering.
|
|
2
2
|
//!
|
|
3
3
|
//! Emits object file with tish_chunk_data and tish_chunk_len symbols.
|
|
4
|
-
//! The link step builds a Rust binary that reads these and runs via
|
|
4
|
+
//! The link step builds a Rust binary that reads these and runs via tishlang_vm.
|
|
5
5
|
|
|
6
6
|
use std::path::Path;
|
|
7
7
|
|
|
@@ -10,7 +10,7 @@ use cranelift::codegen::settings;
|
|
|
10
10
|
use cranelift_module::{DataDescription, Linkage, Module};
|
|
11
11
|
use cranelift_object::{ObjectBuilder, ObjectModule};
|
|
12
12
|
|
|
13
|
-
use
|
|
13
|
+
use tishlang_bytecode::{serialize, Chunk};
|
|
14
14
|
|
|
15
15
|
use crate::CraneliftError;
|
|
16
16
|
|
|
@@ -28,7 +28,7 @@ pub fn lower_and_emit(chunk: &Chunk, object_path: &Path) -> Result<(), Cranelift
|
|
|
28
28
|
message: format!("Failed to finish ISA: {}", e),
|
|
29
29
|
})?;
|
|
30
30
|
|
|
31
|
-
let object_builder = ObjectBuilder::new(isa, "
|
|
31
|
+
let object_builder = ObjectBuilder::new(isa, "tishlang_cranelift", cranelift_module::default_libcall_names())
|
|
32
32
|
.map_err(|e| CraneliftError {
|
|
33
33
|
message: format!("Failed to create ObjectBuilder: {}", e),
|
|
34
34
|
})?;
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
2
|
+
name = "tishlang_cranelift_runtime"
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Runtime for Cranelift-compiled Tish bytecode"
|
|
6
6
|
|
|
7
|
+
license-file = { workspace = true }
|
|
8
|
+
repository = { workspace = true }
|
|
7
9
|
[features]
|
|
8
10
|
default = []
|
|
9
|
-
fs = ["
|
|
10
|
-
process = ["
|
|
11
|
-
http = ["
|
|
11
|
+
fs = ["tishlang_vm/fs"]
|
|
12
|
+
process = ["tishlang_vm/process"]
|
|
13
|
+
http = ["tishlang_vm/http"]
|
|
12
14
|
|
|
13
15
|
[lib]
|
|
14
16
|
crate-type = ["staticlib", "rlib"]
|
|
15
17
|
|
|
16
18
|
[dependencies]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
tishlang_bytecode = { path = "../tish_bytecode" }
|
|
20
|
+
tishlang_vm = { path = "../tish_vm" }
|
|
21
|
+
tishlang_core = { path = "../tish_core" }
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
2
|
+
name = "tishlang_eval"
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Tish tree-walk interpreter"
|
|
6
6
|
|
|
7
|
+
license-file = { workspace = true }
|
|
8
|
+
repository = { workspace = true }
|
|
7
9
|
[features]
|
|
8
10
|
default = []
|
|
9
|
-
http = ["tokio", "reqwest", "futures", "tiny_http", "
|
|
11
|
+
http = ["tokio", "reqwest", "futures", "tiny_http", "tishlang_core/regex", "dep:tishlang_runtime", "tishlang_runtime/http"]
|
|
10
12
|
fs = []
|
|
11
13
|
process = []
|
|
12
|
-
regex = ["dep:fancy-regex", "
|
|
14
|
+
regex = ["dep:fancy-regex", "tishlang_core/regex"]
|
|
13
15
|
tokio = ["dep:tokio"]
|
|
14
|
-
ws = ["dep:
|
|
16
|
+
ws = ["dep:tishlang_runtime", "tishlang_runtime/ws"]
|
|
15
17
|
|
|
16
18
|
[dependencies]
|
|
17
19
|
rand = "0.10.0"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
tishlang_ast = { path = "../tish_ast" }
|
|
21
|
+
tishlang_parser = { path = "../tish_parser" }
|
|
22
|
+
tishlang_core = { path = "../tish_core" }
|
|
21
23
|
reqwest = { version = "0.13.2", default-features = false, features = ["rustls", "json", "stream"], optional = true }
|
|
22
24
|
futures = { version = "0.3.32", optional = true }
|
|
23
25
|
tiny_http = { version = "0.12.0", optional = true }
|
|
24
26
|
fancy-regex = { version = "0.17.0", optional = true }
|
|
25
27
|
tokio = { version = "1.50.0", features = ["rt-multi-thread", "time", "sync"], optional = true }
|
|
26
|
-
|
|
28
|
+
tishlang_runtime = { path = "../tish_runtime", optional = true }
|