#![deny(clippy::disallowed_types)] mod ast; mod bytecode; mod compile; mod errors; mod gc; mod lex; mod parse; mod util; mod vm; use std::io::Write; pub use bumpalo::Bump; pub use lex::*; pub use parse::*; use crate::{ast::Program, gc::RtAlloc}; #[cfg(not(feature = "fxhash"))] #[allow(clippy::disallowed_types)] type HashMap = std::collections::HashMap; #[cfg(feature = "fxhash")] type HashMap = rustc_hash::FxHashMap; #[cfg(not(feature = "fxhash"))] #[allow(clippy::disallowed_types)] type HashSet = std::collections::HashSet; #[cfg(feature = "fxhash")] type HashSet = rustc_hash::FxHashSet; pub struct Config<'io> { pub debug: bool, pub step: bool, pub stdout: &'io mut dyn Write, } pub fn run_program(program: &str, cfg: &mut Config) { if cfg.debug { eprintln!("Config: debug: {}, step: {}", cfg.debug, cfg.step); } let ast_alloc = Bump::new(); // SAFETY: I will try to 🥺 let mut runtime = unsafe { RtAlloc::new() }; let lexer = lex::Lexer::new(program, &mut runtime); let ast = parse::parse(lexer, &ast_alloc); match ast { Ok(ast) => process_ast(program, &ast, runtime, cfg), Err(err) => errors::display_error(program, err), } } fn process_ast(program: &str, ast: &Program, mut runtime: RtAlloc, cfg: &mut Config<'_>) { if cfg.debug { util::dbg("AST:\n", ast); } let bytecode_alloc = Bump::new(); let bytecode = compile::compile(ast, &bytecode_alloc, &mut runtime); match bytecode { Ok(code) => { if cfg.debug { util::dbg("Bytecode:\n", code); } let result = vm::execute(code, runtime, cfg); if let Err(msg) = result { eprintln!("error: {msg}"); } } Err(err) => errors::display_error(program, err), } } // have the code here and not in the fuzzer, it's easier to find when it breaks like this #[doc(hidden)] pub fn _fuzz_compile(program: &str) { // SAFETY: Just this scope let mut runtime = unsafe { RtAlloc::new() }; let ast_alloc = Bump::new(); let lexer = lex::Lexer::new(program, &mut runtime); let ast = parse::parse(lexer, &ast_alloc); if let Ok(ast) = ast { let bytecode_alloc = Bump::new(); let _bytecode = compile::compile(&ast, &bytecode_alloc, &mut runtime); } } #[doc(hidden)] pub fn _fuzz_parse(program: &str) { // SAFETY: Just this scope let mut runtime = unsafe { RtAlloc::new() }; let ast_alloc = Bump::new(); let lexer = lex::Lexer::new(program, &mut runtime); let _ast = parse::parse(lexer, &ast_alloc); } #[doc(hidden)] pub fn _fuzz_lex(program: &str) { // SAFETY: Just this scope let mut runtime = unsafe { RtAlloc::new() }; let lexer = lex::Lexer::new(program, &mut runtime); for _token in lexer {} }