diff options
Diffstat (limited to 'matrix-bin/src/main.rs')
-rw-r--r-- | matrix-bin/src/main.rs | 119 |
1 files changed, 91 insertions, 28 deletions
diff --git a/matrix-bin/src/main.rs b/matrix-bin/src/main.rs index 225b353..64d1b3f 100644 --- a/matrix-bin/src/main.rs +++ b/matrix-bin/src/main.rs @@ -1,6 +1,6 @@ use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs, cell::RefCell, rc::Rc}; use clap::{Parser as ArgParser, ColorChoice}; -use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}, value::Value}; +use matrix_lang::prelude::*; use repl::Repl; mod repl; @@ -12,16 +12,20 @@ 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 + /// Compiles the given program #[arg(short, long)] - repl: bool, + compile: bool, + + /// Optional output for compiled output + #[arg(short, long)] + output: Option<PathBuf>, /// Print out debug information #[arg(short, long)] debug: bool, /// Choses color - #[arg(short, long)] + #[arg(long)] color: Option<ColorChoice>, /// Disables optimizations @@ -29,18 +33,21 @@ pub struct Args { disable_optimizations: bool, } +pub enum Mode { + Repl, + Execute(String), + Compile(String, PathBuf), +} + pub struct State<'a> { parser: Parser, compiler: Compiler<'a>, vm: Rc<RefCell<Vm>>, - repl: bool, color: bool, - #[allow(unused)] - debug: bool, } impl<'a> State<'a> { - pub fn new (args: Args) -> (Self, Option<String>) { + pub fn new (args: Args) -> (Self, Mode) { let stdin = read_stdin(); @@ -53,20 +60,43 @@ impl<'a> State<'a> { file = None; } - let repl = args.repl || file.is_none(); + let mode; + let repl; + if args.compile { + let path = match (args.output, args.file) { + (Some(path), _) => path, + (None, Some(path)) => { + let mut path = path.clone(); + path.set_extension("matc"); + path + }, + (None, None) => { + PathBuf::from("matc.out") + } + }; + let file = file.unwrap_or(String::new()); + mode = Mode::Compile(file, path); + repl = false; + } else if let Some(file) = file { + mode = Mode::Execute(file); + repl = false; + } else { + mode = Mode::Repl; + repl = true; + } + let mut vm = Vm::new(); let parser = ParserBuilder::new() .optimize(!args.disable_optimizations) .build(); - let mut vm = Vm::new(); let compiler = CompilerBuilder::new() .repl(repl) .debug(args.debug) .names(vm.names()) - .globals(vm.global_names()) + .globals(vm.globals()) .build(); - matrix_stdlib::load(&mut vm); + matrix_std::load(&mut vm); let color = match args.color { Some(ColorChoice::Auto) | None => { @@ -76,21 +106,40 @@ impl<'a> State<'a> { Some(ColorChoice::Never) => false, }; - (Self { parser, vm: Rc::new(RefCell::new(vm)), compiler, repl, debug: args.debug, color }, file) + (Self { + parser, + vm: Rc::new(RefCell::new(vm)), + compiler, + color, + }, mode) } - pub fn execute(&mut self, code: String) -> matrix::Result<Value> { - let ast = self.parser.parse(code)?; - let fun = self.compiler.compile(&ast)?; + pub fn execute(&mut self, fun: Rc<Function>) -> Result<Value> { let val = self.vm.try_borrow_mut().unwrap().run(fun)?; Ok(val) } + pub fn compile(&mut self, code: String) -> Result<Rc<Function>> { + let ast = self.parser.parse(code)?; + let fun = self.compiler.compile(&ast)?; + Ok(fun) + } + + pub fn load_program(&mut self, body: String) -> Result<Rc<Function>> { + match Program::load(&body)? { + Some(fun) => { + Ok(fun) + }, + None => { + self.compile(body) + }, + } + } } -pub fn error(err: matrix::Error, state: &State) { +pub fn error(err: Exception, state: &State) { if state.color { - println!("\x1b[31m\x1b[1mError:\x1b[0m {err}"); + println!("\x1b[31mError:\x1b[0m {err}"); } else { println!("Error: {err}"); } @@ -106,19 +155,33 @@ fn read_stdin() -> String { buffer } +fn handle_mode(state: &mut State, mode: Mode) -> Result<()> { + match mode { + Mode::Repl => { + let mut repl = Repl::new(state); + repl.run(); + }, + Mode::Execute(body) => { + let fun = state.load_program(body)?; + state.execute(fun)?; + }, + Mode::Compile(body, path) => { + let fun = state.compile(body)?; + let mut file = File::create(path).map_err(|e| + exception!(IO_EXCEPTION, "{e}") + )?; + Program::save(fun, &mut file)?; + } + }; + Ok(()) +} + fn main() { let args = Args::parse(); - let (mut state, file) = State::new(args); + let (mut state, mode) = State::new(args); - if let Some(file) = file { - if let Err(err) = state.execute(file) { - error(err, &state); - } + if let Err(e) = handle_mode(&mut state, mode) { + error(e, &state); } - - if state.repl { - Repl::new(state).run(); - } - } |