use std::cell::RefCell; use std::sync::Arc; use sexp::SourcePosition; use crate::asm::instr::flatten::jumps_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; use std::sync::atomic::AtomicU32; 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(), scheduler_interval: Default::default(), extensions: parsers_arc.clone(), }); /* numbered labels start with a weird high number to avoid conflicts with user-defined numbered labels */ let label_num = Arc::new(AtomicU32::new(0x7890_0000)); 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(), cr: Default::default(), parked: Default::default(), global_regs: [0; REG_COUNT], ext_data: Default::default(), cr_deadline: None, critical_section: 0, }, const_eval_ti: ti, parsing_expr: false, label_num: label_num.clone() }), }; let ops = parse::parse(source, &SourcePosition::default(), &pcx)?; let ops = jumps_to_skips(ops)?; Ok(Program::new(ops, parsers_arc)?) }