matrix/matrix-bin/src/main.rs

125 lines
3 KiB
Rust
Raw Normal View History

2024-02-27 00:00:42 +00:00
use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs, cell::RefCell, rc::Rc};
use clap::{Parser as ArgParser, ColorChoice};
2024-02-23 16:32:47 +00:00
use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}, value::Value};
2024-02-19 23:38:15 +00:00
use repl::Repl;
mod repl;
2024-02-27 00:00:42 +00:00
mod helper;
2024-02-19 23:38:15 +00:00
#[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,
2024-02-27 00:00:42 +00:00
/// Choses color
#[arg(short, long)]
color: Option<ColorChoice>,
2024-02-19 23:38:15 +00:00
/// Disables optimizations
#[arg(long)]
disable_optimizations: bool,
}
pub struct State<'a> {
parser: Parser,
compiler: Compiler<'a>,
2024-02-27 00:00:42 +00:00
vm: Rc<RefCell<Vm>>,
repl: bool,
color: bool,
#[allow(unused)]
debug: bool,
2024-02-19 23:38:15 +00:00
}
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();
2024-02-23 16:32:47 +00:00
let mut vm = Vm::new();
2024-02-19 23:38:15 +00:00
let compiler = CompilerBuilder::new()
.repl(repl)
.debug(args.debug)
2024-02-23 00:40:09 +00:00
.names(vm.names())
2024-02-23 16:32:47 +00:00
.globals(vm.global_names())
2024-02-19 23:38:15 +00:00
.build();
2024-02-23 16:32:47 +00:00
matrix_stdlib::load(&mut vm);
2024-02-27 00:00:42 +00:00
let color = match args.color {
Some(ColorChoice::Auto) | None => {
io::stdout().is_terminal()
},
Some(ColorChoice::Always) => true,
Some(ColorChoice::Never) => false,
};
(Self { parser, vm: Rc::new(RefCell::new(vm)), compiler, repl, debug: args.debug, color }, file)
2024-02-19 23:38:15 +00:00
}
2024-02-23 16:32:47 +00:00
pub fn execute(&mut self, code: String) -> matrix::Result<Value> {
2024-02-19 23:38:15 +00:00
let ast = self.parser.parse(code)?;
let fun = self.compiler.compile(&ast)?;
2024-02-27 00:00:42 +00:00
let val = self.vm.try_borrow_mut().unwrap().run(fun)?;
2024-02-23 16:32:47 +00:00
Ok(val)
2024-02-19 23:38:15 +00:00
}
}
2024-02-27 00:00:42 +00:00
pub fn error(err: matrix::Error, state: &State) {
if state.color {
println!("\x1b[31m\x1b[1mError:\x1b[0m {err}");
} else {
println!("Error: {err}");
}
2024-02-19 23:38:15 +00:00
}
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) {
2024-02-27 00:00:42 +00:00
error(err, &state);
2024-02-19 23:38:15 +00:00
}
}
if state.repl {
Repl::new(state).run();
}
}