You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.5 KiB
112 lines
3.5 KiB
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;
|
|
use std::path::{Path};
|
|
|
|
pub mod data;
|
|
pub mod error;
|
|
pub mod instr;
|
|
pub mod parse;
|
|
pub mod patches;
|
|
mod read_file;
|
|
use read_file::read_file;
|
|
|
|
pub(crate) fn read_source_file(path: impl AsRef<Path>) -> Result<String, error::CrsnError> {
|
|
trace!("Read source file: {}", path.as_ref().display());
|
|
|
|
let source = read_file(path)?;
|
|
|
|
// remove first line if it looks like a shebang
|
|
let s = if source.starts_with("#!") {
|
|
if let Some(nl) = source.find('\n') {
|
|
(&source[nl + 1..]).to_string()
|
|
} else {
|
|
source
|
|
}
|
|
} else {
|
|
source
|
|
};
|
|
|
|
Ok(s)
|
|
}
|
|
|
|
/// Parse a program from string and assemble a low level instruction sequence from it.
|
|
pub fn assemble(path: impl AsRef<Path>, uniq : &CrsnUniq, mut parsers: Vec<Box<dyn CrsnExtension>>) -> Result<Arc<Program>, error::CrsnError> {
|
|
parsers.insert(0, BuiltinOps::new());
|
|
for p in &mut parsers {
|
|
p.init(uniq);
|
|
}
|
|
|
|
let path = path.as_ref().canonicalize()?;
|
|
let source = read_source_file(&path)?;
|
|
|
|
let parsers_arc = Arc::new(parsers);
|
|
|
|
let ti = Arc::new(ThreadInfo {
|
|
id: ThreadToken(0),
|
|
uniq: Default::default(),
|
|
program: Program::new(vec![], parsers_arc.clone(), vec![path.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(),
|
|
files: vec![
|
|
path,
|
|
],
|
|
active_file: 0
|
|
}),
|
|
};
|
|
|
|
let res = do_parse(&source, &pcx, parsers_arc.clone());
|
|
if let Err(e) = &res {
|
|
if let Some(pos) = e.pos() {
|
|
let f = pcx.state.borrow().files[pos.file as usize].clone();
|
|
eprintln!("Error in source file: {}", f.display());
|
|
}
|
|
}
|
|
res
|
|
}
|
|
|
|
fn do_parse(source: &str, pcx : &ParserContext, parsers_arc : Arc<Vec<Box<dyn CrsnExtension>>>) -> Result<Arc<Program>, error::CrsnError> {
|
|
let ops = parse::parse(source, &SourcePosition::default(), pcx)?;
|
|
let ops = jumps_to_skips(ops)?;
|
|
|
|
Ok(Program::new(ops, parsers_arc, pcx.state.borrow_mut().files.split_off(0))?)
|
|
}
|
|
|