mul/src/main.rs

70 lines
2.0 KiB
Rust

use std::fs::read_to_string;
use std::io::{stdin, stdout, BufRead, Write};
use std::path::Path;
use anyhow::{anyhow, Context, Result};
use mul::cli::{Command, USAGE};
use mul::evaluate::Interpreter;
use mul::parse::{parse_interactive_entry, parse_program};
use mul::syntax::Program;
fn main() -> Result<()> {
let Some(command) = Command::from_environment()? else {
eprintln!("mul\n{USAGE}");
return Ok(())
};
match command {
Command::Parse { path } => {
let program = parse(path.as_path())?;
println!("{program:#?}");
Ok(())
}
Command::Run { path } => {
let program = parse(path.as_path())?;
let mut interpreter = Interpreter::new();
let _result = interpreter.run(&program)?;
Ok(())
}
Command::Repl => repl(),
}
}
fn parse(path: &Path) -> Result<Program> {
let source =
read_to_string(path).with_context(|| format!("failed to open {}", path.display()))?;
parse_program(source.as_str())
.map_err(|e| anyhow!("{e}"))
.with_context(|| format!("failed to parse {}", path.display()))
}
fn repl() -> Result<()> {
let mut stdin = stdin().lock();
let mut stdout = stdout().lock();
let mut interpreter = Interpreter::new();
println!("welcome to M U L");
loop {
let mut line = String::new();
print!("> ");
stdout.flush()?;
stdin
.read_line(&mut line)
.context("Failed to read from stdin")?;
if line.trim().is_empty() {
println!();
continue;
}
let parsed = match parse_interactive_entry(&line) {
Ok(parsed) => parsed,
Err(lalrpop_util::ParseError::UnrecognizedEof { .. }) => break,
Err(e) => {
eprintln!("{e}");
continue;
}
};
let value = interpreter.evaluate_interactive_entry(&parsed)?;
println!("{value}");
}
Ok(())
}