diff options
author | Freya Murphy <freya@freyacat.org> | 2024-02-19 18:38:15 -0500 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2024-02-19 18:38:15 -0500 |
commit | ef4ada62f82ced8116e6ef64bdd773c275ea8195 (patch) | |
tree | ebd6e5c8c60510bf04998b7dccdb440883633763 /matrix-bin/src | |
parent | docs (diff) | |
download | matrix-ef4ada62f82ced8116e6ef64bdd773c275ea8195.tar.gz matrix-ef4ada62f82ced8116e6ef64bdd773c275ea8195.tar.bz2 matrix-ef4ada62f82ced8116e6ef64bdd773c275ea8195.zip |
things
Diffstat (limited to 'matrix-bin/src')
-rw-r--r-- | matrix-bin/src/main.rs | 104 | ||||
-rw-r--r-- | matrix-bin/src/repl.rs | 25 |
2 files changed, 129 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(); + } + +} diff --git a/matrix-bin/src/repl.rs b/matrix-bin/src/repl.rs new file mode 100644 index 0000000..81fd289 --- /dev/null +++ b/matrix-bin/src/repl.rs @@ -0,0 +1,25 @@ +use crate::State; + +pub struct Repl<'a> { + state: State<'a> +} + +impl<'a> Repl<'a> { + + pub fn new(state: State<'a>) -> Self { + Self { state } + } + + pub fn run(&mut self) { + let mut rl = rustyline::DefaultEditor::new().unwrap(); + loop { + let Ok(line) = rl.readline(">> ") else { + break; + }; + if let Err(err) = self.state.execute(line) { + crate::error(err); + } + } + } + +} |