Browse Source

add arg-parsing and fixed seeds

Getty Ritter 2 years ago
parent
commit
869ff8dd2f
4 changed files with 178 additions and 10 deletions
  1. 97 2
      Cargo.lock
  2. 4 1
      Cargo.toml
  3. 18 0
      src/interp.rs
  4. 59 7
      src/main.rs

+ 97 - 2
Cargo.lock

@@ -22,6 +22,15 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "ansi_term"
 version = "0.12.1"
@@ -118,6 +127,21 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term 0.11.0",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
 [[package]]
 name = "clipboard-win"
 version = "4.2.2"
@@ -184,6 +208,12 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
 
+[[package]]
+name = "dtoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
+
 [[package]]
 name = "either"
 version = "1.6.1"
@@ -438,6 +468,12 @@ dependencies = [
  "vcpkg",
 ]
 
+[[package]]
+name = "linked-hash-map"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
+
 [[package]]
 name = "lock_api"
 version = "0.4.5"
@@ -490,8 +526,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
 name = "matzo"
 version = "0.1.0"
 dependencies = [
- "ansi_term",
+ "ansi_term 0.12.1",
  "anyhow",
+ "clap",
  "lalrpop",
  "lalrpop-util",
  "logos",
@@ -499,6 +536,8 @@ dependencies = [
  "rand",
  "regex",
  "rustyline",
+ "serde",
+ "serde_yaml",
  "string-interner",
  "titlecase",
  "vergen",
@@ -670,7 +709,7 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc"
 dependencies = [
- "ansi_term",
+ "ansi_term 0.12.1",
  "ctor",
  "diff",
  "output_vt100",
@@ -860,6 +899,32 @@ name = "serde"
 version = "1.0.130"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.130"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af"
+dependencies = [
+ "dtoa",
+ "indexmap",
+ "serde",
+ "yaml-rust",
+]
 
 [[package]]
 name = "siphasher"
@@ -903,6 +968,12 @@ dependencies = [
  "precomputed-hash",
 ]
 
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
 [[package]]
 name = "syn"
 version = "1.0.81"
@@ -940,6 +1011,15 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
 [[package]]
 name = "thiserror"
 version = "1.0.30"
@@ -1067,6 +1147,12 @@ version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
 
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
 [[package]]
 name = "vergen"
 version = "5.1.17"
@@ -1118,3 +1204,12 @@ name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]

+ 4 - 1
Cargo.toml

@@ -28,6 +28,8 @@ ansi_term = "*"
 string-interner = "*"
 anyhow = "*"
 titlecase = "*"
+serde = { version = "1.0", features = ["derive"] }
+clap = "2.33"
 
 [build-dependencies]
 vergen = "*"
@@ -37,4 +39,5 @@ version = "*"
 features = ["lexer"]
 
 [dev-dependencies]
-pretty_assertions = "*"
+pretty_assertions = "*"
+serde_yaml = "0.8"

+ 18 - 0
src/interp.rs

@@ -289,6 +289,24 @@ impl State {
         s
     }
 
+    /// This initializes a new `State` and adds all the builtin
+    /// functions to the root scope
+    pub fn new_from_seed(seed: u64) -> State {
+        let s = State {
+            root_scope: RefCell::new(HashMap::new()),
+            rand: RefCell::new(Box::new(SeededRNG::from_seed(seed))),
+            parser: crate::grammar::StmtsParser::new(),
+            ast: RefCell::new(ASTArena::new()),
+        };
+        for builtin in BUILTINS {
+            let sym = s.ast.borrow_mut().add_string(builtin.name);
+            s.root_scope
+                .borrow_mut()
+                .insert(sym, Thunk::Builtin(builtin));
+        }
+        s
+    }
+
     /// Get the underlying AST. (This is mostly useful for testing
     /// purposes, where we don't want to have a function do the
     /// parsing and evaluating for us at the same time.)

+ 59 - 7
src/main.rs

@@ -1,12 +1,58 @@
 use matzo::interp::State;
 
+use clap::{Arg, App};
+
+#[derive(Debug)]
+struct Opts {
+    seed: Option<u64>,
+    files: Vec<String>,
+}
+
+impl Opts {
+    fn parse() -> Opts {
+        let matches = App::new("Matzo")
+            .setting(clap::AppSettings::TrailingVarArg)
+            .version(format!("git {}", env!("VERGEN_GIT_SHA")).as_ref())
+            .author("Getty Ritter <matzo@infinitenegativeutility.com>")
+            .about("A language for random text")
+            .arg(Arg::with_name("seed")
+                 .short("s")
+                 .long("seed")
+                 .value_name("NUMBER")
+                 .help("Sets a custom RNG seed")
+                 .takes_value(true))
+            .arg(Arg::with_name("input")
+                 .value_name("FILES")
+                 .help("Files to evaluate")
+                 .multiple(true)
+                 .takes_value(true))
+            .get_matches();
+
+        let seed = if let Some(s) = matches.value_of("seed") {
+            Some(s.parse().unwrap())
+        } else {
+            None
+        };
+        let mut files = Vec::new();
+        if let Some(fs) = matches.values_of("FILES") {
+            files.extend(fs.map(|x| x.to_string()));
+        }
+        Opts { seed, files }
+    }
+}
+
 fn matzo_version() -> String {
     format!("matzo (git {})", env!("VERGEN_GIT_SHA"))
 }
 
-fn run_repl() -> Result<(), Box<dyn std::error::Error>> {
+fn run_repl(seed: Option<u64>) -> Result<(), Box<dyn std::error::Error>> {
     let mut rl = rustyline::Editor::<matzo::repl::Repl>::new();
-    let state = std::rc::Rc::new(std::cell::RefCell::new(State::new()));
+    let state = if let Some(s) = seed {
+        State::new_from_seed(s)
+    } else {
+        State::new()
+    };
+    let state = std::rc::Rc::new(std::cell::RefCell::new(state));
     rl.set_helper(Some(matzo::repl::Repl::new(state.clone())));
     println!("{}", ansi_term::Colour::Blue.bold().paint(matzo_version()),);
     println!("{}", ansi_term::Colour::Blue.paint("(work-in-progress)"),);
@@ -30,15 +76,21 @@ fn run_repl() -> Result<(), Box<dyn std::error::Error>> {
 }
 
 fn main() {
-    let args = std::env::args().skip(1).collect::<Vec<String>>();
-    if args.is_empty() {
-        run_repl().unwrap();
+    let opts = Opts::parse();
+
+    if opts.files.is_empty() {
+        run_repl(opts.seed).unwrap();
         return;
     }
 
-    for arg in args {
+    let state = if let Some(s) = opts.seed {
+        State::new_from_seed(s)
+    } else {
+        State::new()
+    };
+    for arg in opts.files {
         let buf = std::fs::read_to_string(arg).unwrap();
-        if let Err(err) = State::new().run(&buf) {
+        if let Err(err) = state.run(&buf) {
             eprintln!(
                 "{} {}",
                 ansi_term::Colour::Red.bold().paint("error:"),