@tishlang/tish 1.1.2 → 1.3.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @tishlang/tish
2
2
 
3
- [Tish](https://github.com/tishlang/tish) is a minimal TypeScript/JavaScript–compatible language: run with an interpreter, use a REPL, or compile to native binaries.
3
+ [Tish](https://github.com/tishlang/tish) is a minimal TypeScript/JavaScript–compatible language: run with an interpreter, use a REPL, or build native binaries and other targets.
4
4
 
5
5
  This npm package ships the **Tish CLI** for Node.js **22+**. It includes platform-specific native binaries; the `tish` command picks the right one for your OS and CPU.
6
6
 
@@ -25,14 +25,14 @@ npx @tishlang/tish hello.tish
25
25
  npx @tishlang/tish run src/main.tish
26
26
  ```
27
27
 
28
- Compile to a native executable:
28
+ Build a native executable:
29
29
 
30
30
  ```bash
31
- npx @tishlang/tish compile app.tish -o app
31
+ npx @tishlang/tish build app.tish -o app
32
32
  ./app
33
33
  ```
34
34
 
35
- Native compilation uses the Rust backend by default (requires [Rust](https://rustup.rs) and `cargo` on your PATH). The package includes the Tish workspace source (`Cargo.toml`, `crates/`, `justfile`) so `tish compile` can run `cargo build` for your program. For pure Tish without native imports, use `--native-backend cranelift` (no Rust toolchain needed).
35
+ Native builds use the Rust backend by default (requires [Rust](https://rustup.rs) and `cargo` on your PATH). The package includes the Tish workspace source (`Cargo.toml`, `crates/`, `justfile`) so `tish build` can run `cargo build` for your program. For pure Tish without native imports, use `--native-backend cranelift` (no Rust toolchain needed).
36
36
 
37
37
  Start the REPL:
38
38
 
package/bin/tish.js CHANGED
@@ -19,7 +19,7 @@ if (!fs.existsSync(binPath)) {
19
19
 
20
20
  // Convenience: "npx @tishlang/tish FILE [args]" → "tish run FILE [args]"
21
21
  const args = process.argv.slice(2);
22
- const subcommands = ['run', 'repl', 'compile', 'dump-ast'];
22
+ const subcommands = ['run', 'repl', 'build', 'dump-ast'];
23
23
  const first = args[0];
24
24
  const looksLikeFile = first && !first.startsWith('-') && !subcommands.includes(first);
25
25
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tishlang"
3
- version = "1.1.2"
3
+ version = "1.3.0"
4
4
  edition = "2021"
5
5
  description = "Tish CLI - run, REPL, compile to native"
6
6
  license-file = { workspace = true }
@@ -1,10 +1,10 @@
1
- //! Tish CLI - run, REPL, compile to native.
1
+ //! Tish CLI - run, REPL, build to native or other targets.
2
2
 
3
3
  mod repl_completion;
4
4
 
5
5
  use std::cell::RefCell;
6
6
  use std::fs;
7
- use std::io::{self, IsTerminal, Write};
7
+ use std::io::{self, IsTerminal, Read, Write};
8
8
  use std::path::{Path, PathBuf};
9
9
  use std::rc::Rc;
10
10
 
@@ -23,7 +23,8 @@ pub(crate) struct Cli {
23
23
 
24
24
  #[derive(Parser)]
25
25
  struct RunArgs {
26
- #[arg(required = true)]
26
+ /// Path to a `.tish` file, or `-` to read the program from stdin (like `node -`).
27
+ #[arg(required = true, allow_hyphen_values = true)]
27
28
  file: String,
28
29
  #[arg(long, default_value = "vm")]
29
30
  backend: String,
@@ -45,7 +46,7 @@ struct ReplArgs {
45
46
  }
46
47
 
47
48
  #[derive(Parser)]
48
- struct CompileArgs {
49
+ struct BuildArgs {
49
50
  #[arg(short, long, default_value = "tish_out")]
50
51
  output: String,
51
52
  #[arg(long, default_value = "native")]
@@ -66,8 +67,8 @@ pub(crate) enum Commands {
66
67
  Run(RunArgs),
67
68
  /// Interactive REPL
68
69
  Repl(ReplArgs),
69
- /// Compile to native binary or JavaScript
70
- Compile(CompileArgs),
70
+ /// Build native binary, wasm, wasi, or JavaScript output
71
+ Build(BuildArgs),
71
72
  /// Parse and dump AST
72
73
  #[command(name = "dump-ast")]
73
74
  DumpAst {
@@ -77,14 +78,26 @@ pub(crate) enum Commands {
77
78
  }
78
79
 
79
80
  fn main() {
80
- let cli = Cli::parse();
81
81
  let no_opt_env = std::env::var_os("TISH_NO_OPTIMIZE")
82
82
  .map(|v| v == "1" || v == "true" || v == "yes")
83
83
  .unwrap_or(false);
84
+
85
+ // `tish -` (like `node -` / `bun -`); clap would treat `-` as an invalid subcommand.
86
+ let argv: Vec<String> = std::env::args().collect();
87
+ if argv.len() == 2 && argv[1] == "-" {
88
+ let result = run_stdin_pipe("vm", &[], no_opt_env, true);
89
+ if let Err(e) = result {
90
+ eprintln!("Error: {}", e);
91
+ std::process::exit(1);
92
+ }
93
+ return;
94
+ }
95
+
96
+ let cli = Cli::parse();
84
97
  let result = match cli.command {
85
98
  Some(Commands::Run(a)) => run_file(&a.file, &a.backend, &a.features, a.no_optimize || no_opt_env),
86
99
  Some(Commands::Repl(a)) => run_repl(&a.backend, a.no_optimize || no_opt_env),
87
- Some(Commands::Compile(a)) => compile_file(
100
+ Some(Commands::Build(a)) => build_file(
88
101
  &a.file,
89
102
  &a.output,
90
103
  &a.target,
@@ -93,7 +106,14 @@ fn main() {
93
106
  a.no_optimize || no_opt_env,
94
107
  ),
95
108
  Some(Commands::DumpAst { file }) => dump_ast(&file),
96
- None => run_repl("vm", false), // No args = REPL
109
+ None => {
110
+ if io::stdin().is_terminal() {
111
+ run_repl("vm", no_opt_env)
112
+ } else {
113
+ // `echo '...' | tish` — run script from stdin (Bun-style)
114
+ run_stdin_pipe("vm", &[], no_opt_env, false)
115
+ }
116
+ }
97
117
  };
98
118
 
99
119
  if let Err(e) = result {
@@ -102,49 +122,97 @@ fn main() {
102
122
  }
103
123
  }
104
124
 
105
- fn run_file(path: &str, backend: &str, _features: &[String], no_optimize: bool) -> Result<(), String> {
106
- let path = Path::new(path).canonicalize().map_err(|e| format!("Cannot resolve {}: {}", path, e))?;
107
- let project_root = path.parent().and_then(|p| {
108
- if p.file_name().and_then(|n| n.to_str()) == Some("src") {
109
- p.parent()
110
- } else {
111
- Some(p)
125
+ /// Read stdin and run as Tish. If `fail_on_empty`, `tish run -` / `tish -` get an error; if false, empty stdin exits 0.
126
+ fn run_stdin_pipe(
127
+ backend: &str,
128
+ features: &[String],
129
+ no_optimize: bool,
130
+ fail_on_empty: bool,
131
+ ) -> Result<(), String> {
132
+ let mut source = String::new();
133
+ io::stdin()
134
+ .read_to_string(&mut source)
135
+ .map_err(|e| format!("Cannot read stdin: {}", e))?;
136
+ if source.trim().is_empty() {
137
+ if fail_on_empty {
138
+ return Err(
139
+ "No source on stdin. Example: echo 'console.log(1)' | tish or tish run -".into(),
140
+ );
112
141
  }
113
- });
142
+ return Ok(());
143
+ }
144
+ run_stdin_source(&source, backend, features, no_optimize)
145
+ }
114
146
 
115
- let program = if path.extension().map(|e| e == "js") == Some(true) {
116
- let prog = tishlang_js_to_tish::convert(&fs::read_to_string(&path).map_err(|e| format!("{}", e))?)
117
- .map_err(|e| format!("{}", e))?;
118
- if no_optimize {
119
- prog
120
- } else {
121
- tishlang_opt::optimize(&prog)
122
- }
147
+ fn run_stdin_source(
148
+ source: &str,
149
+ backend: &str,
150
+ _features: &[String],
151
+ no_optimize: bool,
152
+ ) -> Result<(), String> {
153
+ let cwd = std::env::current_dir().map_err(|e| e.to_string())?;
154
+ let modules = tishlang_compile::resolve_project_from_stdin(source, &cwd)?;
155
+ tishlang_compile::detect_cycles(&modules)?;
156
+ let prog = tishlang_compile::merge_modules(modules)?;
157
+ let program = if no_optimize {
158
+ prog
159
+ } else {
160
+ tishlang_opt::optimize(&prog)
161
+ };
162
+ run_program(&program, backend, no_optimize)
163
+ }
164
+
165
+ fn run_file(path: &str, backend: &str, features: &[String], no_optimize: bool) -> Result<(), String> {
166
+ let program = if path == "-" {
167
+ return run_stdin_pipe(backend, features, no_optimize, true);
123
168
  } else {
124
- let modules = tishlang_compile::resolve_project(&path, project_root)?;
125
- tishlang_compile::detect_cycles(&modules)?;
126
- let prog = tishlang_compile::merge_modules(modules)?;
127
- if no_optimize {
128
- prog
169
+ let path =
170
+ Path::new(path).canonicalize().map_err(|e| format!("Cannot resolve {}: {}", path, e))?;
171
+ let project_root = path.parent().and_then(|p| {
172
+ if p.file_name().and_then(|n| n.to_str()) == Some("src") {
173
+ p.parent()
174
+ } else {
175
+ Some(p)
176
+ }
177
+ });
178
+
179
+ if path.extension().map(|e| e == "js") == Some(true) {
180
+ let prog = tishlang_js_to_tish::convert(&fs::read_to_string(&path).map_err(|e| format!("{}", e))?)
181
+ .map_err(|e| format!("{}", e))?;
182
+ if no_optimize {
183
+ prog
184
+ } else {
185
+ tishlang_opt::optimize(&prog)
186
+ }
129
187
  } else {
130
- tishlang_opt::optimize(&prog)
188
+ let modules = tishlang_compile::resolve_project(&path, project_root)?;
189
+ tishlang_compile::detect_cycles(&modules)?;
190
+ let prog = tishlang_compile::merge_modules(modules)?;
191
+ if no_optimize {
192
+ prog
193
+ } else {
194
+ tishlang_opt::optimize(&prog)
195
+ }
131
196
  }
132
197
  };
133
198
 
199
+ run_program(&program, backend, no_optimize)
200
+ }
201
+
202
+ fn run_program(program: &tishlang_ast::Program, backend: &str, no_optimize: bool) -> Result<(), String> {
134
203
  if backend == "interp" {
135
204
  let mut eval = tishlang_eval::Evaluator::new();
136
- let value = eval.eval_program(&program)?;
205
+ let value = eval.eval_program(program)?;
137
206
  if !matches!(value, tishlang_eval::Value::Null) {
138
207
  println!("{}", tishlang_eval::format_value_for_console(&value, tishlang_core::use_console_colors()));
139
208
  }
140
209
  return Ok(());
141
210
  }
142
211
 
143
- // VM backend (bytecode) - supports native imports when built with fs/http/process features
144
212
  let chunk = if no_optimize {
145
- tishlang_bytecode::compile_unoptimized(&program).map_err(|e| e.to_string())?
213
+ tishlang_bytecode::compile_unoptimized(program).map_err(|e| e.to_string())?
146
214
  } else {
147
- tishlang_bytecode::compile(&program).map_err(|e| e.to_string())?
215
+ tishlang_bytecode::compile(program).map_err(|e| e.to_string())?
148
216
  };
149
217
  let value = tishlang_vm::run(&chunk)?;
150
218
  if !matches!(value, tishlang_core::Value::Null) {
@@ -385,7 +453,7 @@ fn compile_to_js(input_path: &Path, output_path: &str, optimize: bool) -> Result
385
453
  }
386
454
 
387
455
  #[allow(clippy::vec_init_then_push)]
388
- fn compile_file(
456
+ fn build_file(
389
457
  input_path: &str,
390
458
  output_path: &str,
391
459
  target: &str,
@@ -512,10 +580,10 @@ mod cli_tests {
512
580
  use super::{Cli, Commands};
513
581
 
514
582
  #[test]
515
- fn compile_js_target_parses() {
583
+ fn build_js_target_parses() {
516
584
  let cli = Cli::try_parse_from([
517
585
  "tish",
518
- "compile",
586
+ "build",
519
587
  "m.tish",
520
588
  "--target",
521
589
  "js",
@@ -524,8 +592,17 @@ mod cli_tests {
524
592
  ])
525
593
  .unwrap();
526
594
  match cli.command {
527
- Some(Commands::Compile(a)) => assert_eq!(a.file, "m.tish"),
528
- _ => panic!("expected Compile"),
595
+ Some(Commands::Build(a)) => assert_eq!(a.file, "m.tish"),
596
+ _ => panic!("expected Build"),
597
+ }
598
+ }
599
+
600
+ #[test]
601
+ fn run_stdin_marker_parses_as_file() {
602
+ let cli = Cli::try_parse_from(["tish", "run", "-"]).unwrap();
603
+ match cli.command {
604
+ Some(Commands::Run(a)) => assert_eq!(a.file, "-"),
605
+ _ => panic!("expected Run"),
529
606
  }
530
607
  }
531
608
  }
@@ -40,7 +40,7 @@ fn target_dir() -> PathBuf {
40
40
  .unwrap_or_else(|_| workspace_root().join("target"))
41
41
  }
42
42
 
43
- /// Cache dir for tish compile outputs (under target/ so CI rust-cache restores it).
43
+ /// Cache dir for tish build outputs (under target/ so CI rust-cache restores it).
44
44
  fn integration_compile_cache_dir() -> PathBuf {
45
45
  target_dir().join("integration_compile_cache")
46
46
  }
@@ -56,7 +56,7 @@ fn file_content_hash(path: &Path) -> u64 {
56
56
  }
57
57
 
58
58
  /// Compile a .tish file with the given backend, using a persistent cache so we only run
59
- /// `tish compile` when the file or backend changed. Returns path to the compiled artifact
59
+ /// `tish build` when the file or backend changed. Returns path to the compiled artifact
60
60
  /// (binary, .js, or .wasm) in a temp dir; caller may run it and then delete it.
61
61
  ///
62
62
  /// Cache is keyed by backend (native, cranelift, js, wasi) so e.g. cranelift and wasi
@@ -73,7 +73,7 @@ fn compile_cached(bin: &Path, path: &Path, backend: &str) -> PathBuf {
73
73
  let ext = if cfg!(target_os = "windows") { ".exe" } else { "" };
74
74
  let cached = cache_base.join(format!("{}_{}{}", stem, hash8, ext));
75
75
  let args = vec![
76
- OsString::from("compile"),
76
+ OsString::from("build"),
77
77
  OsString::from(path),
78
78
  OsString::from("-o"),
79
79
  OsString::from(&cached),
@@ -84,7 +84,7 @@ fn compile_cached(bin: &Path, path: &Path, backend: &str) -> PathBuf {
84
84
  let ext = if cfg!(target_os = "windows") { ".exe" } else { "" };
85
85
  let cached = cache_base.join(format!("{}_{}{}", stem, hash8, ext));
86
86
  let args = vec![
87
- OsString::from("compile"),
87
+ OsString::from("build"),
88
88
  OsString::from(path),
89
89
  OsString::from("-o"),
90
90
  OsString::from(&cached),
@@ -96,7 +96,7 @@ fn compile_cached(bin: &Path, path: &Path, backend: &str) -> PathBuf {
96
96
  "js" => {
97
97
  let cached = cache_base.join(format!("{}_{}.js", stem, hash8));
98
98
  let args = vec![
99
- OsString::from("compile"),
99
+ OsString::from("build"),
100
100
  OsString::from(path),
101
101
  OsString::from("--target"),
102
102
  OsString::from("js"),
@@ -109,7 +109,7 @@ fn compile_cached(bin: &Path, path: &Path, backend: &str) -> PathBuf {
109
109
  let out_base = cache_base.join(format!("{}_{}", stem, hash8));
110
110
  let artifact = out_base.with_extension("wasm");
111
111
  let args = vec![
112
- OsString::from("compile"),
112
+ OsString::from("build"),
113
113
  OsString::from(path),
114
114
  OsString::from("-o"),
115
115
  OsString::from(&out_base),
@@ -126,7 +126,7 @@ fn compile_cached(bin: &Path, path: &Path, backend: &str) -> PathBuf {
126
126
  .args(compile_args)
127
127
  .current_dir(workspace_root())
128
128
  .output()
129
- .expect("run tish compile");
129
+ .expect("run tish build");
130
130
  assert!(
131
131
  out.status.success(),
132
132
  "Compile failed for {} ({}): {}",
@@ -203,13 +203,13 @@ fn test_async_await_compile_via_binary() {
203
203
  if path.exists() && bin.exists() {
204
204
  let out = std::env::temp_dir().join("tish_async_test_out");
205
205
  let compile_result = Command::new(&bin)
206
- .args(["compile", path.to_string_lossy().as_ref(), "-o", out.to_string_lossy().as_ref()])
206
+ .args(["build", path.to_string_lossy().as_ref(), "-o", out.to_string_lossy().as_ref()])
207
207
  .current_dir(workspace_root())
208
208
  .output();
209
- let compile_out = compile_result.expect("run tish compile");
209
+ let compile_out = compile_result.expect("run tish build");
210
210
  assert!(
211
211
  compile_out.status.success(),
212
- "tish compile failed: {}",
212
+ "tish build failed: {}",
213
213
  String::from_utf8_lossy(&compile_out.stderr)
214
214
  );
215
215
  // Run compiled binary to validate non-blocking fetchAll executes correctly
@@ -245,13 +245,13 @@ fn test_async_parallel_vs_sequential_timing() {
245
245
 
246
246
  // Compile both
247
247
  let compile_par = Command::new(&bin)
248
- .args(["compile", parallel_src.to_string_lossy().as_ref(), "-o", out_parallel.to_string_lossy().as_ref()])
248
+ .args(["build", parallel_src.to_string_lossy().as_ref(), "-o", out_parallel.to_string_lossy().as_ref()])
249
249
  .current_dir(workspace_root())
250
250
  .output();
251
251
  assert!(compile_par.as_ref().unwrap().status.success(), "compile parallel: {}", String::from_utf8_lossy(&compile_par.as_ref().unwrap().stderr));
252
252
 
253
253
  let compile_seq = Command::new(&bin)
254
- .args(["compile", sequential_src.to_string_lossy().as_ref(), "-o", out_sequential.to_string_lossy().as_ref()])
254
+ .args(["build", sequential_src.to_string_lossy().as_ref(), "-o", out_sequential.to_string_lossy().as_ref()])
255
255
  .current_dir(workspace_root())
256
256
  .output();
257
257
  assert!(compile_seq.as_ref().unwrap().status.success(), "compile sequential: {}", String::from_utf8_lossy(&compile_seq.as_ref().unwrap().stderr));
@@ -1,5 +1,5 @@
1
1
  //! `new` lowering for non-JS targets: `construct(callee, args)` approximates JS `[[Construct]]`.
2
- //! Browser-exact behavior remains on `tish compile --target js`.
2
+ //! Browser-exact behavior remains on `tish build --target js`.
3
3
 
4
4
  use std::cell::RefCell;
5
5
  use std::rc::Rc;
@@ -15,7 +15,7 @@ pub use codegen::CompileError;
15
15
  pub use resolve::{
16
16
  detect_cycles, extract_native_import_features, has_external_native_imports, has_native_imports,
17
17
  is_builtin_native_spec, merge_modules, resolve_native_modules, resolve_project,
18
- ResolvedNativeModule,
18
+ resolve_project_from_stdin, ResolvedNativeModule,
19
19
  };
20
20
  pub use types::{RustType, TypeContext};
21
21
 
@@ -242,6 +242,59 @@ pub fn resolve_project(
242
242
  .collect())
243
243
  }
244
244
 
245
+ /// Resolve modules when the entry program is read from stdin (`tish run -`).
246
+ /// Relative file imports resolve from `project_root` (typically [`std::env::current_dir()`]).
247
+ /// The synthetic entry path `<stdin>` is not a real file; dependencies load from disk as usual.
248
+ pub fn resolve_project_from_stdin(
249
+ source: &str,
250
+ project_root: &Path,
251
+ ) -> Result<Vec<ResolvedModule>, String> {
252
+ let root_canon = project_root
253
+ .canonicalize()
254
+ .map_err(|e| format!("Cannot canonicalize project root {}: {}", project_root.display(), e))?;
255
+
256
+ let stdin_path = root_canon.join("<stdin>");
257
+ let program = tishlang_parser::parse(source)
258
+ .map_err(|e| format!("Parse error (stdin): {}", e))?;
259
+
260
+ let mut visited = HashSet::new();
261
+ let mut path_to_module: HashMap<PathBuf, Program> = HashMap::new();
262
+ let mut load_order: Vec<PathBuf> = Vec::new();
263
+
264
+ let from_dir = stdin_path
265
+ .parent()
266
+ .unwrap_or_else(|| Path::new("."));
267
+
268
+ for stmt in &program.statements {
269
+ if let Statement::Import { from, .. } = stmt {
270
+ if is_native_import(from) {
271
+ continue;
272
+ }
273
+ let dep_path = resolve_import_path(from, from_dir, &root_canon)?;
274
+ if !path_to_module.contains_key(&dep_path) {
275
+ load_module_recursive(
276
+ &dep_path,
277
+ &root_canon,
278
+ &mut visited,
279
+ &mut path_to_module,
280
+ &mut load_order,
281
+ )?;
282
+ }
283
+ }
284
+ }
285
+
286
+ path_to_module.insert(stdin_path.clone(), program);
287
+ load_order.push(stdin_path);
288
+
289
+ Ok(load_order
290
+ .into_iter()
291
+ .map(|p| {
292
+ let program = path_to_module.remove(&p).unwrap();
293
+ ResolvedModule { path: p, program }
294
+ })
295
+ .collect())
296
+ }
297
+
245
298
  fn load_module_recursive(
246
299
  module_path: &Path,
247
300
  project_root: &Path,
@@ -14,4 +14,4 @@ tishlang_ast = { path = "../tish_ast", version = ">=0.1" }
14
14
  tishlang_compile = { path = "../tish_compile", version = ">=0.1" }
15
15
  tishlang_opt = { path = "../tish_opt", version = ">=0.1" }
16
16
  tishlang_parser = { path = "../tish_parser", version = ">=0.1" }
17
- tishlang_ui = { path = "../tish_ui", default-features = false, features = ["compiler"] }
17
+ tishlang_ui = { path = "../tish_ui", version = ">=0.1", default-features = false, features = ["compiler"] }
@@ -1,4 +1,4 @@
1
- //! Runtime linked into the `tish compile --native-backend cranelift` executable.
1
+ //! Runtime linked into the `tish build --native-backend cranelift` executable.
2
2
  //!
3
3
  //! **`tish_run_chunk`** deserializes embedded bytecode and runs **`tishlang_vm`** — the same
4
4
  //! execution engine as `tish run --backend vm`. The crate name is historical; this is not
@@ -1593,7 +1593,7 @@ impl Evaluator {
1593
1593
  self.construct_value(&c, &arg_vals)
1594
1594
  }
1595
1595
  Expr::JsxElement { .. } | Expr::JsxFragment { .. } => Err(EvalError::Error(
1596
- "JSX is not supported in the interpreter. Use 'tish compile --target js' to compile to JavaScript.".to_string(),
1596
+ "JSX is not supported in the interpreter. Use 'tish build --target js' to compile to JavaScript.".to_string(),
1597
1597
  )),
1598
1598
  Expr::NativeModuleLoad { spec, export_name, .. } => {
1599
1599
  self.load_builtin_export(spec.as_ref(), export_name.as_ref())
package/justfile CHANGED
@@ -9,8 +9,8 @@
9
9
  # just run run hello.tish # runs via interpreter
10
10
  # tish run hello.tish # if tish is in PATH
11
11
  #
12
- # 2. BUILD (Compile to Native) - Create standalone executable:
13
- # just run compile hello.tish -o hello # compiles to native binary
12
+ # 2. BUILD (native binary) - Create standalone executable:
13
+ # just run build hello.tish -o hello # builds native binary
14
14
  # ./hello # run the standalone binary
15
15
  #
16
16
  # ═══════════════════════════════════════════════════════════════════════════════
@@ -72,17 +72,17 @@ run-regex *ARGS:
72
72
  cargo run --release --no-default-features --features regex -- {{ARGS}}
73
73
 
74
74
  # ═══════════════════════════════════════════════════════════════════════════════
75
- # COMPILE TISH PROGRAMS TO NATIVE BINARIES
75
+ # BUILD TISH PROGRAMS TO NATIVE BINARIES (just recipe name: compile → invokes `tish build`)
76
76
  # ═══════════════════════════════════════════════════════════════════════════════
77
77
 
78
- # Compile a .tish file to native binary (with all features)
78
+ # Build a .tish file to native binary (with all features)
79
79
  # Usage: just compile hello.tish hello
80
80
  compile INPUT OUTPUT:
81
- cargo run --release --features full -- compile {{INPUT}} -o {{OUTPUT}}
81
+ cargo run --release --features full -- build {{INPUT}} -o {{OUTPUT}}
82
82
 
83
83
  # Compile with secure mode (no dangerous features)
84
84
  compile-secure INPUT OUTPUT:
85
- cargo run --release --no-default-features -- compile {{INPUT}} -o {{OUTPUT}}
85
+ cargo run --release --no-default-features -- build {{INPUT}} -o {{OUTPUT}}
86
86
 
87
87
  # Build compiler WASM (for playground, REPL, try-it). Output: tish_compiler.js, tish_compiler_bg.wasm
88
88
  # Requires: rustup target add wasm32-unknown-unknown, cargo install wasm-bindgen-cli
@@ -94,17 +94,17 @@ build-compiler-wasm OUT_DIR:
94
94
  # Compile to WebAssembly (browser) - produces .wasm, .js, .html
95
95
  # Requires: rustup target add wasm32-unknown-unknown, cargo install wasm-bindgen-cli
96
96
  compile-wasm INPUT OUTPUT:
97
- cargo run --release -- compile {{INPUT}} -o {{OUTPUT}} --target wasm
97
+ cargo run --release -- build {{INPUT}} -o {{OUTPUT}} --target wasm
98
98
 
99
99
  # Compile to WebAssembly (Wasmtime/WASI) - single .wasm, run with: wasmtime OUTPUT.wasm
100
100
  # Requires: rustup target add wasm32-wasip1, wasmtime (curl -sSf https://wasmtime.dev/install.sh | bash)
101
101
  compile-wasi INPUT OUTPUT:
102
- cargo run --release -- compile {{INPUT}} -o {{OUTPUT}} --target wasi
102
+ cargo run --release -- build {{INPUT}} -o {{OUTPUT}} --target wasi
103
103
 
104
104
  # Compile with specific features
105
105
  # Usage: just compile-with "http fs" hello.tish hello
106
106
  compile-with FEATURES INPUT OUTPUT:
107
- cargo run --release --no-default-features --features "{{FEATURES}}" -- compile {{INPUT}} -o {{OUTPUT}}
107
+ cargo run --release --no-default-features --features "{{FEATURES}}" -- build {{INPUT}} -o {{OUTPUT}}
108
108
 
109
109
  # ═══════════════════════════════════════════════════════════════════════════════
110
110
  # TESTS
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tishlang/tish",
3
- "version": "1.1.2",
4
- "description": "Tish - minimal TS/JS-compatible language. Run, REPL, compile to native.",
3
+ "version": "1.3.0",
4
+ "description": "Tish - minimal TS/JS-compatible language. Run, REPL, build to native or other targets.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
7
7
  "type": "git",
Binary file
Binary file
Binary file
Binary file
Binary file