diff options
Diffstat (limited to 'matrix-bin/src/main.rs')
-rw-r--r-- | matrix-bin/src/main.rs | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/matrix-bin/src/main.rs b/matrix-bin/src/main.rs new file mode 100644 index 0000000..7e3c3c6 --- /dev/null +++ b/matrix-bin/src/main.rs @@ -0,0 +1,104 @@ +use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs}; +use clap::Parser as ArgParser; +use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}}; +use repl::Repl; + +mod repl; + +#[derive(Debug, ArgParser)] +#[command(version, long_about = None)] +pub struct Args { + /// A path to a input program. Uses stdin if not specified. + file: Option<PathBuf>, + + /// Runs a repl, loading the provided program first + #[arg(short, long)] + repl: bool, + + /// Print out debug information + #[arg(short, long)] + debug: bool, + + /// Disables optimizations + #[arg(long)] + disable_optimizations: bool, +} + +pub struct State<'a> { + parser: Parser, + compiler: Compiler<'a>, + vm: Vm, + repl: bool +} + +impl<'a> State<'a> { + pub fn new (args: Args) -> (Self, Option<String>) { + + let stdin = read_stdin(); + + let file; + if let Some(path) = &args.file { + file = Some(fs::read_to_string(path).unwrap()); + } else if stdin.len() > 0 { + file = Some(stdin); + } else { + file = None; + } + + let repl = args.repl || file.is_none(); + + let parser = ParserBuilder::new() + .optimize(!args.disable_optimizations) + .build(); + let vm = Vm::new(); + let compiler = CompilerBuilder::new() + .repl(repl) + .debug(args.debug) + .globals(vm.globals()) + .build(); + + (Self { parser, vm, compiler, repl }, file) + } + + pub fn execute(&mut self, code: String) -> matrix::Result<()> { + let ast = self.parser.parse(code)?; + let fun = self.compiler.compile(&ast)?; + let val = self.vm.run(fun)?; + if self.repl { + println!("{val}"); + } + Ok(()) + } + +} + +pub fn error(err: matrix::Error) { + println!("\x1b[31m\x1b[1mError:\x1b[0m {err}"); +} + +fn read_stdin() -> String { + let mut buffer = String::new(); + let mut stdin = io::stdin(); + if stdin.is_terminal() { + return String::new(); + } + stdin.read_to_string(&mut buffer).unwrap(); + buffer +} + +fn main() { + + let args = Args::parse(); + let (mut state, file) = State::new(args); + + if let Some(file) = file { + if let Err(err) = state.execute(file) { + error(err); + } + } + + if state.repl { + Repl::new(state).run(); + } + +} |