main.rs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. use matzo::interp::State;
  2. use clap::{App, Arg};
  3. #[derive(Debug)]
  4. struct Opts {
  5. seed: Option<u64>,
  6. files: Vec<String>,
  7. }
  8. impl Opts {
  9. fn parse() -> Opts {
  10. let matches = App::new("Matzo")
  11. .setting(clap::AppSettings::TrailingVarArg)
  12. .version(format!("git {}", env!("VERGEN_GIT_SHA")).as_ref())
  13. .author("Getty Ritter <matzo@infinitenegativeutility.com>")
  14. .about("A language for random text")
  15. .arg(
  16. Arg::with_name("seed")
  17. .short("s")
  18. .long("seed")
  19. .value_name("NUMBER")
  20. .help("Sets a custom RNG seed")
  21. .takes_value(true),
  22. )
  23. .arg(
  24. Arg::with_name("input")
  25. .value_name("FILES")
  26. .help("Files to evaluate")
  27. .multiple(true)
  28. .takes_value(true),
  29. )
  30. .get_matches();
  31. let seed = matches.value_of("seed").map(|s| s.parse().unwrap());
  32. let mut files = Vec::new();
  33. if let Some(fs) = matches.values_of("input") {
  34. files.extend(fs.map(|x| x.to_string()));
  35. }
  36. Opts { seed, files }
  37. }
  38. }
  39. fn matzo_version() -> String {
  40. format!("matzo (git {})", env!("VERGEN_GIT_SHA"))
  41. }
  42. fn run_repl(seed: Option<u64>) -> Result<(), Box<dyn std::error::Error>> {
  43. let mut rl = rustyline::Editor::<matzo::repl::Repl>::new();
  44. let state = if let Some(s) = seed {
  45. State::new_from_seed(s)
  46. } else {
  47. State::new()
  48. };
  49. let state = std::rc::Rc::new(std::cell::RefCell::new(state));
  50. rl.set_helper(Some(matzo::repl::Repl::new(state.clone())));
  51. println!("{}", ansi_term::Colour::Blue.bold().paint(matzo_version()),);
  52. println!("{}", ansi_term::Colour::Blue.paint("(work-in-progress)"),);
  53. loop {
  54. let line = match rl.readline(">>> ") {
  55. Ok(ln) => ln,
  56. Err(rustyline::error::ReadlineError::Eof)
  57. | Err(rustyline::error::ReadlineError::Interrupted) => return Ok(()),
  58. err => err?,
  59. };
  60. if let Err(err) = state.borrow_mut().run_repl(&line) {
  61. eprintln!(
  62. "{} {}",
  63. ansi_term::Colour::Red.bold().paint("error:"),
  64. ansi_term::Colour::Red.paint(format!("{}", err)),
  65. );
  66. }
  67. }
  68. }
  69. fn main() {
  70. let opts = Opts::parse();
  71. if opts.files.is_empty() {
  72. run_repl(opts.seed).unwrap();
  73. return;
  74. }
  75. let state = if let Some(s) = opts.seed {
  76. State::new_from_seed(s)
  77. } else {
  78. State::new()
  79. };
  80. for arg in opts.files {
  81. let buf = std::fs::read_to_string(arg).unwrap();
  82. if let Err(err) = state.run(&buf) {
  83. eprintln!(
  84. "{} {}",
  85. ansi_term::Colour::Red.bold().paint("error:"),
  86. ansi_term::Colour::Red.paint(format!("{}", err)),
  87. );
  88. }
  89. }
  90. }