mod parser; mod evaluator; mod emitter; use clap::Parser; use std::io; use std::io::prelude::*; use std::fs::File; use std::path::PathBuf; #[derive(Parser, Debug)] #[clap(author, version, about = "Interpreter for Deelang")] struct Cli { #[clap(help="Specify a file to run")] file: Option, #[clap(short, long, help="Only parse, do not evaluate")] parse: bool, #[clap(short, long, help="Cross-compile to ECMAScript")] ecmascript: bool, #[clap(long, help="Only run the pre-processor")] preprocess: bool, } fn repl(cli: &Cli) { let mut global = evaluator::Env::global(); let mut toplevel = emitter::LexicalContext::toplevel(); let mut out = io::stdout(); loop { let mut line = String::new(); io::stdin().read_line(&mut line).unwrap(); let tree = parser::parse_stmt(&line); if cli.parse { println!("{:#?}", tree); } else if cli.ecmascript { emitter::emit(&mut out, &tree, &mut toplevel).ok(); } else { evaluator::eval(&tree, &mut global); } } } fn script(cli: &Cli) { let mut file = File::open(cli.file.as_ref().unwrap()).expect("Could not read file"); let mut prgm = String::new(); file.read_to_string(&mut prgm).unwrap(); if cli.preprocess { println!("{}", parser::preprocess(&prgm)); return; } let tree = parser::parse(&prgm); if cli.parse { println!("{:#?}", tree); } else if cli.ecmascript { let mut out = io::stdout(); emitter::emit_injector(&mut out).ok(); let mut toplevel = emitter::LexicalContext::toplevel(); emitter::emit_all(&mut out, &tree, &mut toplevel).ok(); } else { todo!(); } } fn main() { let cli = Cli::parse(); match cli.file { None => repl(&cli), Some(_) => script(&cli), } }