2024-02-27 05:18:43 +00:00
|
|
|
use clap::{ColorChoice, Parser};
|
|
|
|
use std::{path::PathBuf, process::ExitCode, rc::Rc};
|
2024-11-04 18:31:53 +00:00
|
|
|
use talc_lang::{
|
2024-11-12 20:40:51 +00:00
|
|
|
compiler::compile,
|
|
|
|
lstring::LString,
|
2024-11-14 19:16:33 +00:00
|
|
|
optimize::optimize,
|
2024-12-21 05:55:45 +00:00
|
|
|
parser,
|
|
|
|
prelude::*,
|
|
|
|
serial,
|
2024-11-12 20:40:51 +00:00
|
|
|
symbol::Symbol,
|
|
|
|
value::{function::disasm_recursive, Value},
|
2024-11-14 19:16:33 +00:00
|
|
|
vm::Vm,
|
2024-11-04 18:31:53 +00:00
|
|
|
};
|
2024-02-27 05:18:43 +00:00
|
|
|
|
|
|
|
mod helper;
|
2024-11-04 18:25:31 +00:00
|
|
|
mod repl;
|
2024-02-21 16:04:18 +00:00
|
|
|
|
2024-02-23 19:54:34 +00:00
|
|
|
#[derive(Parser, Debug)]
|
|
|
|
#[command(version, about, long_about = None)]
|
|
|
|
struct Args {
|
2024-11-12 20:40:51 +00:00
|
|
|
/// Start the repl
|
2024-02-27 05:18:43 +00:00
|
|
|
#[arg(short, long)]
|
|
|
|
repl: bool,
|
2024-02-23 19:54:34 +00:00
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
/// Show disassembled bytecode
|
2024-02-27 05:18:43 +00:00
|
|
|
#[arg(short, long)]
|
|
|
|
disasm: bool,
|
2024-02-23 19:54:34 +00:00
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
/// Show generated AST
|
|
|
|
#[arg(short = 'a', long)]
|
|
|
|
show_ast: bool,
|
|
|
|
|
|
|
|
/// Compile to a bytecode file
|
|
|
|
#[arg(short, long)]
|
|
|
|
compile: Option<PathBuf>,
|
|
|
|
|
2024-12-14 20:38:50 +00:00
|
|
|
/// Don't apply optimizations
|
|
|
|
#[arg(long)]
|
|
|
|
no_opt: bool,
|
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
/// Set history file
|
2024-11-04 18:25:31 +00:00
|
|
|
#[arg(short = 'H', long)]
|
2024-03-08 00:38:57 +00:00
|
|
|
histfile: Option<PathBuf>,
|
|
|
|
|
2024-02-27 05:18:43 +00:00
|
|
|
/// enable or disable color
|
2024-11-04 18:25:31 +00:00
|
|
|
#[arg(short, long, default_value = "auto")]
|
2024-02-27 05:18:43 +00:00
|
|
|
color: ColorChoice,
|
2024-11-12 20:40:51 +00:00
|
|
|
|
|
|
|
// file to run and arguments to pass
|
|
|
|
#[arg()]
|
|
|
|
args: Vec<LString>,
|
2024-02-23 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2024-11-04 17:59:05 +00:00
|
|
|
fn exec(name: Symbol, src: &str, args: &Args) -> ExitCode {
|
2024-11-12 20:40:51 +00:00
|
|
|
let mut vm = Vm::new(256, args.args.clone());
|
2024-02-27 05:18:43 +00:00
|
|
|
talc_std::load_all(&mut vm);
|
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
let mut ex = match parser::parse(src) {
|
2024-02-27 05:18:43 +00:00
|
|
|
Ok(ex) => ex,
|
|
|
|
Err(e) => {
|
|
|
|
eprintln!("Error: {e}");
|
|
|
|
return ExitCode::FAILURE
|
2024-11-04 18:25:31 +00:00
|
|
|
}
|
2024-02-27 05:18:43 +00:00
|
|
|
};
|
|
|
|
|
2024-12-14 20:38:50 +00:00
|
|
|
if !args.no_opt {
|
|
|
|
optimize(&mut ex);
|
|
|
|
}
|
2024-11-12 20:40:51 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
};
|
2024-02-27 05:18:43 +00:00
|
|
|
|
|
|
|
if args.disasm {
|
|
|
|
if let Err(e) = disasm_recursive(&func, &mut std::io::stderr()) {
|
|
|
|
eprintln!("Error: {e}");
|
|
|
|
return ExitCode::FAILURE
|
2024-02-21 16:04:18 +00:00
|
|
|
}
|
|
|
|
}
|
2024-02-27 05:18:43 +00:00
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
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,
|
2024-12-21 05:55:45 +00:00
|
|
|
Ok(Value::Int(n)) => ExitCode::from(n.to_u64().unwrap_or(1) as u8),
|
2024-11-12 20:40:51 +00:00
|
|
|
_ => ExitCode::SUCCESS,
|
2024-02-27 05:18:43 +00:00
|
|
|
}
|
2024-02-23 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() -> ExitCode {
|
2024-02-27 05:18:43 +00:00
|
|
|
let args = Args::parse();
|
2024-02-23 19:54:34 +00:00
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
if args.repl || args.args.is_empty() {
|
|
|
|
if args.compile.is_some() {
|
|
|
|
eprintln!("Error: cannot compile in REPL mode");
|
|
|
|
return ExitCode::FAILURE
|
|
|
|
}
|
2024-02-27 05:18:43 +00:00
|
|
|
return repl::repl(&args)
|
|
|
|
}
|
2024-02-22 19:27:35 +00:00
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
let file = args.args[0].as_ref();
|
2024-11-04 17:59:05 +00:00
|
|
|
|
2024-11-12 20:40:51 +00:00
|
|
|
match std::fs::read_to_string(file.to_os_str()) {
|
|
|
|
Ok(s) => exec(Symbol::get(file), &s, &args),
|
2024-02-27 05:18:43 +00:00
|
|
|
Err(e) => {
|
2024-11-12 20:40:51 +00:00
|
|
|
eprintln!("Error opening source file: {e}");
|
2024-02-27 05:18:43 +00:00
|
|
|
ExitCode::FAILURE
|
|
|
|
}
|
|
|
|
}
|
2024-02-21 16:04:18 +00:00
|
|
|
}
|