Commit Diff


commit - c5de16c57b82f6abd2a6ebbe2cbed524347bac05
commit + 79f214478cb2c969a713b514eaef9496ab501490
blob - ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba
blob + fe6bb941ff7e1fb38488bb5c42014a9aeb8f961f
--- .gitignore
+++ .gitignore
@@ -1 +1,3 @@
-/target
+target
+*.dv
+*.gif
blob - 1a84a0966df721c2c027591b4b9ac8d6913f5d73
blob + 6050ffabec52b70b71a6b0baef7e71a114a1bb4f
--- Cargo.lock
+++ Cargo.lock
@@ -3,6 +3,71 @@
 version = 3
 
 [[package]]
+name = "anstream"
+version = "0.6.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
+[[package]]
+name = "autovis"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "pest",
+ "pest_derive",
+]
+
+[[package]]
 name = "block-buffer"
 version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -16,6 +81,52 @@ name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "4.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
 
 [[package]]
 name = "cpufeatures"
@@ -47,14 +158,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "dotvis"
-version = "0.1.0"
-dependencies = [
- "pest",
- "pest_derive",
-]
-
-[[package]]
 name = "generic-array"
 version = "0.14.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -65,6 +168,18 @@ dependencies = [
 ]
 
 [[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+
+[[package]]
 name = "libc"
 version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -157,6 +272,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
 name = "syn"
 version = "2.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -206,7 +327,86 @@ source = "registry+https://github.com/rust-lang/crates
 checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
 name = "version_check"
 version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
blob - 38731a70a889e12000e18791b8a66394d668c4c6
blob + 0b42331bd0da0d8281ec5a68155484dc0a78672c
--- Cargo.toml
+++ Cargo.toml
@@ -1,8 +1,10 @@
 [package]
-name = "dotvis"
+name = "autovis"
 version = "0.1.0"
 edition = "2021"
 
 [dependencies]
+anyhow = "1.0.86"
+clap = { version = "4.5.7", features = ["derive"] }
 pest = "2.7.10"
 pest_derive = "2.7.10"
blob - /dev/null
blob + 1f763def82bb7b3655169f50f4d8aba37aa0abd4 (mode 644)
--- /dev/null
+++ src/cli.rs
@@ -0,0 +1,15 @@
+use std::path::PathBuf;
+
+use clap::Parser;
+
+#[derive(Parser)]
+pub struct Cli {
+    pub rules: PathBuf,
+    pub input: String,
+
+    #[arg(short, long)]
+    pub output: Option<PathBuf>,
+
+    #[arg(short, long, default_value_t = 100)]
+    pub delay: u32,
+}
blob - dc25e626edaf9acb9c66b01542810d85de4a6932
blob + 5f1f8388cc24ea4e6eb173bbbb53c067d47f1fa7
--- src/main.rs
+++ src/main.rs
@@ -1,75 +1,112 @@
-use std::{path::Path, process::{Command, Stdio}, io::Write};
+use std::{io::{ErrorKind, Write}, path::Path, process::{Command, Stdio}};
+use anyhow::{bail, Context, Result};
+use clap::Parser;
+use crate::{ast::Machine, cli::Cli};
 
-use ast::Machine;
-
 mod ast;
+mod cli;
 mod parser;
 
-fn write(mach: &Machine, tmpdir: &Path, id: usize) {
+fn write(mach: &Machine, tmpdir: &Path, id: usize) -> Result<()> {
     let path = tmpdir.join(format!("{id}.png"));
+
     let mut cmd = Command::new("dot")
         .args(&["-Tpng", "-o"])
         .arg(path)
         .stdin(Stdio::piped())
         .spawn()
-        .unwrap();
+        .context("failed to spawn dot")?;
 
-    let mut stdin = cmd.stdin.take().unwrap();
+    let mut stdin = cmd
+	.stdin
+	.take()
+	.context("failed to take stdin")?;
 
-    writeln!(&mut stdin, "{mach}").unwrap();
+    writeln!(&mut stdin, "{mach}")
+	.context("failed to print machine")?;
+
     drop(stdin);
 
-    cmd.wait().unwrap();
+    cmd
+	.wait()
+	.context("failed to wait for completion")?;
+
+    Ok(())
 }
 
-fn compile(out: &Path, tmpdir: &Path, num: usize) {
-    let size = imgsize(&tmpdir.join(format!("{}.png", num - 1)));
+fn imgsize(path: &Path) -> Result<String> {
+    let data = Command::new("identify")
+        .args(&["-format", "%wx%h"])
+	.arg(path)
+	.output()
+	.context("failed to spawn identify")?
+	.stdout;
+    let s = String::from_utf8(data)
+	.context("failed to parse output of identify")?;
+    Ok(s)
+}
+
+fn compile(out: &Path, tmpdir: &Path, num: usize, delay: u32) -> Result<()> {
+    let size = imgsize(&tmpdir.join(format!("{}.png", num - 1)))
+        .context("failed to determine gif dimensions")?;
+    
     let mut cmd = Command::new("convert");
+    let delay = delay.to_string();
+
     for i in 0..num {
 	let path = tmpdir.join(format!("{i}.png"));
-	cmd.args(&["-delay", "100"]).arg(path);
+	cmd.args(&["-delay", &delay]).arg(path);
     }
     let st = cmd
         .args(&["-extent", &size])
 	.arg(out)
 	.status()
-	.unwrap()
+	.context("failed to spawn convert")?
 	.success();
 
     if !st {
-	panic!("not ok");
+	bail!("convert failed");
     }
-}
 
-fn imgsize(path: &Path) -> String {
-    let data = Command::new("identify")
-        .args(&["-format", "%wx%h"])
-	.arg(path)
-	.output()
-	.unwrap()
-	.stdout;
-    String::from_utf8(data).unwrap()
+    Ok(())
 }
 
-fn main() {
-    let tmpdir = std::env::temp_dir();
-    let input = "011";
-    let s = std::fs::read_to_string("test.dv").expect("failed to read");
-    let mut mach = crate::parser::parse(&s).expect("failed to parse");
+fn main() -> Result<()> {
+    let cli = Cli::parse();
+    
+    let tmpdir = std::env::temp_dir()
+	.join("autovis");
 
-    write(&mach, &tmpdir, 0);
+    std::fs::create_dir_all(&tmpdir)
+        .or_else(|e| match e.kind() {
+	    ErrorKind::AlreadyExists => Ok(()),
+	    _ => Err(e),
+	})
+        .context("failed to create temporary directory")?;
+    
+    let mach = std::fs::read_to_string(&cli.rules)
+        .context("faile to read automaton")?;
+    let mut mach = crate::parser::parse(&mach)
+	.context("failed to parse automaton")?;
+
+    write(&mach, &tmpdir, 0)?;
+
     let mut id = 1;
 
-    for ch in input.chars() {
+    for ch in cli.input.chars() {
 	if !mach.feed(ch) {
 	    break;
 	}
 
-	write(&mach, &tmpdir, id);
+	write(&mach, &tmpdir, id)?;
 	id = id + 1;
     }
 
-    let out = Path::new("test.gif");
-    compile(out, &tmpdir, id);
+    let out = cli
+        .output
+	.as_deref()
+        .unwrap_or(Path::new("a.gif"));
+    compile(out, &tmpdir, id, cli.delay)?;
 
+    Ok(())
 }
blob - 71fd85b7c74a163cd6f80dacc8695839566c9c77
blob + 02b1288f3b75a0ed3978c9abda3ef8d4308494b8
--- src/parser.rs
+++ src/parser.rs
@@ -1,8 +1,6 @@
 use std::collections::BTreeMap;
-
 use pest::{error::Error, iterators::Pair, Parser};
 use pest_derive::Parser;
-
 use crate::ast::{Edge, Machine, Node};
 
 #[derive(Parser)]