use clap::{ColorChoice, Parser}; use std::{path::PathBuf, process::ExitCode, rc::Rc}; use talc_lang::{ compiler::compile, lstring::LString, optimize::optimize, parser, prelude::*, serial, symbol::Symbol, value::{function::disasm_recursive, Value}, vm::Vm, }; mod helper; mod repl; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// Start the repl #[arg(short, long)] repl: bool, /// Show disassembled bytecode #[arg(short, long)] disasm: bool, /// Show generated AST #[arg(short = 'a', long)] show_ast: bool, /// Compile to a bytecode file #[arg(short, long)] compile: Option, /// Don't apply optimizations #[arg(long)] no_opt: bool, /// Set history file #[arg(short = 'H', long)] histfile: Option, /// enable or disable color #[arg(short, long, default_value = "auto")] color: ColorChoice, // file to run and arguments to pass #[arg()] args: Vec, } fn exec(name: Symbol, src: &str, args: &Args) -> ExitCode { let mut vm = Vm::new(256, args.args.clone()); talc_std::load_all(&mut vm); let mut ex = match parser::parse(src) { Ok(ex) => ex, Err(e) => { eprintln!("Error: {e}"); return ExitCode::FAILURE } }; if !args.no_opt { optimize(&mut ex); } if args.show_ast { eprintln!("{}", ex); } let func = match compile(&ex, Some(name)) { Ok(f) => Rc::new(f), Err(e) => { eprintln!("Error: {e}"); return ExitCode::FAILURE } }; if args.disasm { if let Err(e) = disasm_recursive(&func, &mut std::io::stderr()) { eprintln!("Error: {e}"); return ExitCode::FAILURE } } if let Some(path) = &args.compile { let f = std::fs::File::options() .write(true) .truncate(true) .create(true) .open(path); let mut w = match f { Ok(f) => f, Err(e) => { eprintln!("Error opening output file: {e}"); return ExitCode::FAILURE } }; if let Err(e) = serial::write_program(&mut w, &func) { eprintln!("Error writing bytecode: {e}"); return ExitCode::FAILURE } return ExitCode::SUCCESS } let res = vm.run_function(func.clone(), vec![func.into()]); match res { Err(e) => { eprintln!("{e}"); ExitCode::FAILURE } Ok(Value::Bool(false)) => ExitCode::FAILURE, Ok(Value::Int(n)) => ExitCode::from(n.to_u64().unwrap_or(1) as u8), _ => ExitCode::SUCCESS, } } fn main() -> ExitCode { let args = Args::parse(); if args.repl || args.args.is_empty() { if args.compile.is_some() { eprintln!("Error: cannot compile in REPL mode"); return ExitCode::FAILURE } return repl::repl(&args) } let file = args.args[0].as_ref(); match std::fs::read_to_string(file.to_os_str()) { Ok(s) => exec(Symbol::get(file), &s, &args), Err(e) => { eprintln!("Error opening source file: {e}"); ExitCode::FAILURE } } }