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.
69 lines
1.8 KiB
69 lines
1.8 KiB
4 years ago
|
mod op;
|
||
|
mod cond;
|
||
|
|
||
|
pub use op::Op;
|
||
|
pub use cond::Cond;
|
||
|
use crate::data::literal::{Label, RoutineName};
|
||
|
use std::sync::atomic::{AtomicU32};
|
||
|
use std::collections::HashMap;
|
||
|
use crate::error::{AsmError, Error};
|
||
|
|
||
|
/// A higher-level instruction
|
||
|
pub struct Instr {
|
||
|
pub op: Op,
|
||
|
pub branches: Option<Vec<(Cond, Vec<Instr>)>>,
|
||
|
}
|
||
|
|
||
|
/// A routine
|
||
|
pub struct Routine {
|
||
|
pub name: RoutineName,
|
||
|
pub body: Vec<Instr>,
|
||
|
}
|
||
|
|
||
|
/// A trait for something that can turn into multiple instructions
|
||
|
pub trait Flatten {
|
||
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error>;
|
||
|
}
|
||
|
|
||
|
impl Flatten for Instr {
|
||
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
|
||
|
let mut ops = vec![self.op];
|
||
|
|
||
|
if let Some(branches) = self.branches {
|
||
|
let labels = HashMap::<Cond, u32>::new();
|
||
|
let _branch_count = branches.len();
|
||
|
for (_cnt, (cond, branch)) in branches.into_iter().enumerate() {
|
||
|
if labels.contains_key(&cond) {
|
||
|
return Err(Error::Asm(AsmError::ConditionalAlreadyUsed(cond)));
|
||
|
}
|
||
|
|
||
|
let next_lbl = Label::unique(label_num);
|
||
|
ops.push(Op::JumpIf(!cond, next_lbl.clone()));
|
||
|
|
||
|
for branch_instr in branch {
|
||
|
ops.extend(branch_instr.flatten(label_num)?);
|
||
|
}
|
||
|
|
||
|
ops.push(Op::Label(next_lbl));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(ops)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Flatten for Routine {
|
||
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
|
||
|
let mut ops = vec![
|
||
|
Op::Routine(self.name.clone()),
|
||
|
];
|
||
|
|
||
|
for instr in self.body {
|
||
|
ops.extend(instr.flatten(label_num)?);
|
||
|
}
|
||
|
|
||
|
ops.push(Op::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())));
|
||
|
Ok(ops)
|
||
|
}
|
||
|
}
|