matrix/matrix-bin/src/main.rs

105 lines
2.4 KiB
Rust
Raw Normal View History

2024-02-19 23:38:15 +00:00
use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs};
use clap::Parser as ArgParser;
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;
#[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();
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-19 23:38:15 +00:00
(Self { parser, vm, compiler, repl }, file)
}
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)?;
let val = self.vm.run(fun)?;
2024-02-23 16:32:47 +00:00
Ok(val)
2024-02-19 23:38:15 +00:00
}
}
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();
}
}