use std::cell::RefCell; use std::sync::Arc; use sexp::SourcePosition; use crate::asm::instr::flatten::labels_to_skips; use crate::asm::parse::{ParserContext, ParserState}; use crate::module::{CrsnExtension, CrsnUniq}; use crate::runtime::program::Program; use crate::builtin::BuiltinOps; use crate::runtime::run_thread::{RunState, ThreadInfo, ThreadToken}; use crate::runtime::frame::REG_COUNT; pub mod data; pub mod error; pub mod instr; pub mod parse; pub mod patches; /// Parse a program from string and assemble a low level instruction sequence from it. pub fn assemble(source: &str, uniq : &CrsnUniq, mut parsers: Vec>) -> Result, error::CrsnError> { parsers.insert(0, BuiltinOps::new()); for p in &mut parsers { p.init(uniq); } let parsers_arc = Arc::new(parsers); // remove first line if it looks like a shebang let source = if source.starts_with("#!") { if let Some(nl) = source.find('\n') { &source[nl + 1..] } else { source } } else { source }; let ti = Arc::new(ThreadInfo { id: ThreadToken(0), uniq: Default::default(), program: Program::new(vec![], parsers_arc.clone()).unwrap(), cycle_time: Default::default(), extensions: parsers_arc.clone(), }); let pcx = ParserContext { parsers: &parsers_arc, state: RefCell::new(ParserState { reg_aliases: Default::default(), reg_alias_stack: vec![], global_reg_aliases: Default::default(), constants: Default::default(), // This is a fake thread to pass to constant expressions when evaluating them. // This allows to evaluate nearly all instructions at compile time. const_eval: RunState { thread_info: ti.clone(), frame: Default::default(), call_stack: vec![], global_regs: [0; REG_COUNT], ext_data: Default::default() }, const_eval_ti: ti, parsing_expr: false }), }; let ops = parse::parse(source, &SourcePosition::default(), &pcx)?; let ops = labels_to_skips(ops)?; Ok(Program::new(ops, parsers_arc)?) }