summaryrefslogtreecommitdiff
path: root/matrix-bin/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'matrix-bin/src/main.rs')
-rw-r--r--matrix-bin/src/main.rs104
1 files changed, 104 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();
+ }
+
+}