diff options
Diffstat (limited to 'matrix-bin/src')
-rw-r--r-- | matrix-bin/src/helper.rs | 8 | ||||
-rw-r--r-- | matrix-bin/src/main.rs | 119 | ||||
-rw-r--r-- | matrix-bin/src/repl.rs | 53 |
3 files changed, 130 insertions, 50 deletions
diff --git a/matrix-bin/src/helper.rs b/matrix-bin/src/helper.rs index 95e0848..df40946 100644 --- a/matrix-bin/src/helper.rs +++ b/matrix-bin/src/helper.rs @@ -1,7 +1,6 @@ use std::{borrow::Cow, rc::Rc, cell::RefCell}; - -use matrix::{lex::{Lexer, TokenData, Token}, vm::Vm}; use rustyline::{validate::{Validator, ValidationResult, ValidationContext}, highlight::Highlighter, Helper, Hinter, completion::Completer}; +use matrix_lang::prelude::*; #[derive(Helper, Hinter)] pub struct MatrixHelper { @@ -205,6 +204,7 @@ impl Highlighter for MatrixHelper { T::Else | T::While | T::Let | + T::Const | T::Function | T::Continue | T::Break | @@ -290,12 +290,12 @@ impl Completer for MatrixHelper { } let _ = (line, pos, ctx); - let globals = self.vm.borrow().global_names(); + let globals = self.vm.borrow().globals(); let names: Vec<Rc<str>> = globals .borrow() .clone() .into_iter() - .filter(|n| n.starts_with(&buf)) + .filter_map(|n| if n.name.starts_with(&buf) { Some(n.name.clone()) } else { None }) .collect(); if buf.is_empty() { 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(); - } - } diff --git a/matrix-bin/src/repl.rs b/matrix-bin/src/repl.rs index f2964d4..fe9975f 100644 --- a/matrix-bin/src/repl.rs +++ b/matrix-bin/src/repl.rs @@ -1,21 +1,26 @@ use std::{io::Write, sync::atomic::Ordering}; - -use matrix::{value::Value, vm::Interupt}; -use rustyline::{Config, EditMode, ColorMode, Editor, CompletionType}; +use rustyline::{Config, EditMode, ColorMode, Editor, CompletionType, error::ReadlineError}; +use matrix_lang::prelude::*; use crate::{State, helper::MatrixHelper}; -pub struct Repl<'a> { - state: State<'a> +pub struct Repl<'s, 'a> { + state: &'s mut State<'a> } -impl<'a> Repl<'a> { +impl<'s, 'a> Repl<'s, 'a> { - pub fn new(state: State<'a>) -> Self { + pub fn new(state: &'s mut State<'a>) -> Self { Self { state } } - pub fn run(&mut self) { + fn execute(&mut self, line: String) -> Result<Value> { + let fun = self.state.compile(line)?; + let val = self.state.execute(fun)?; + Ok(val) + } + + pub fn run(&mut self) { let interupt = self.state.vm.borrow().interupt(); ctrlc::set_handler(move || { @@ -23,26 +28,33 @@ impl<'a> Repl<'a> { }).unwrap(); let config = Config::builder() + .indent_size(4) + .edit_mode(EditMode::Emacs) .check_cursor_position(true) .completion_type(CompletionType::List) - .edit_mode(EditMode::Emacs) .color_mode(if self.state.color { ColorMode::Enabled } else { ColorMode::Disabled }) .build(); let helper = MatrixHelper::new(self.state.vm.clone()); + let histfile = std::env::var("MATRIX_HISTORY").ok(); + let mut rl = Editor::with_config(config).unwrap(); rl.set_helper(Some(helper)); + if let Some(hf) = &histfile { + rl.load_history(hf).ok(); + } loop { - let Ok(line) = rl.readline(">> ") else { - break; - }; - if let Err(_) = rl.add_history_entry(&line) { - break; + let line = match rl.readline(">> ") { + Ok(line) => line, + Err(ReadlineError::Eof) => break, + Err(_) => continue, }; - match self.state.execute(line) { - Err(err) => crate::error(err, &self.state), + + rl.add_history_entry(&line).ok(); + + match self.execute(line) { Ok(val) => { if val != Value::Nil { if self.state.color { @@ -52,8 +64,13 @@ impl<'a> Repl<'a> { } } } - } - let _ = std::io::stdout().flush(); + Err(err) => crate::error(err, &self.state), + }; + std::io::stdout().flush().ok(); + } + + if let Some(hf) = &histfile { + rl.save_history(hf).ok(); } } |