154 lines
3.3 KiB
Rust
154 lines
3.3 KiB
Rust
mod addr;
|
|
mod id;
|
|
mod symbol;
|
|
pub use addr::*;
|
|
pub use id::*;
|
|
pub use symbol::*;
|
|
|
|
use crate::{arch::Arch, backend::LinkedProgram, io::CompilerMsg};
|
|
|
|
pub struct Program<A: Arch> {
|
|
pub ro_data: Vec<Data>,
|
|
pub funcs: Vec<Func<A>>,
|
|
pub entry: Option<Symbol>,
|
|
pub external: Vec<External>,
|
|
pub call_convs: Vec<A::CallConv>,
|
|
|
|
sym_info: Vec<SymInfo>,
|
|
sym_count: usize,
|
|
}
|
|
|
|
pub struct Data {
|
|
pub bytes: Vec<u8>,
|
|
pub sym: Symbol,
|
|
}
|
|
|
|
pub struct Func<A: Arch> {
|
|
pub params: Vec<VarId>,
|
|
pub body: Body<A>,
|
|
pub sym: Symbol,
|
|
pub conv: usize,
|
|
}
|
|
|
|
pub struct External {
|
|
pub file: String,
|
|
pub syms: Vec<Symbol>,
|
|
}
|
|
|
|
pub struct SymInfo {
|
|
pub name: String,
|
|
pub external: bool,
|
|
}
|
|
|
|
pub type Body<A> = Vec<Instr<A>>;
|
|
|
|
pub enum Instr<A: Arch> {
|
|
Set {
|
|
dst: VarId,
|
|
src: Vec<u8>,
|
|
},
|
|
Call {
|
|
dst: VarId,
|
|
f: FnId,
|
|
args: Vec<VarId>,
|
|
},
|
|
Copy {
|
|
dst: VarId,
|
|
src: VarId,
|
|
},
|
|
Add {
|
|
dst: VarId,
|
|
src1: VarId,
|
|
src2: VarId,
|
|
},
|
|
If {
|
|
cond: VarId,
|
|
then: Body<A>,
|
|
else_: Body<A>,
|
|
},
|
|
Loop(Body<A>),
|
|
Return(Option<VarId>),
|
|
Break(Option<VarId>),
|
|
Asm(A::Asm),
|
|
}
|
|
|
|
impl<A: Arch> Program<A> {
|
|
pub fn encode_data(&self, data: &mut Vec<u8>, sym_tab: &mut SymTable<A::Addr>) {
|
|
for d in &self.ro_data {
|
|
let addr = A::Addr::from_len(data.len());
|
|
data.extend(&d.bytes);
|
|
sym_tab.insert(d.sym, addr);
|
|
}
|
|
}
|
|
|
|
pub fn ro_data(&mut self, name: impl Into<String>, bytes: impl Into<Vec<u8>>) -> Symbol {
|
|
let bytes = bytes.into();
|
|
let sym = self.reserve(SymInfo {
|
|
name: name.into(),
|
|
external: false,
|
|
});
|
|
self.ro_data.push(Data { bytes, sym });
|
|
sym
|
|
}
|
|
|
|
pub fn func(&mut self, name: impl Into<String>, instrs: impl Into<Vec<Instr<A>>>) -> Symbol {
|
|
let instrs = instrs.into();
|
|
let sym = self.reserve(SymInfo {
|
|
name: name.into(),
|
|
external: false,
|
|
});
|
|
self.funcs.push(Func { body: instrs, sym });
|
|
sym
|
|
}
|
|
|
|
pub fn external<const LEN: usize>(
|
|
&mut self,
|
|
file: impl Into<String>,
|
|
names: [impl Into<String>; LEN],
|
|
) -> [Symbol; LEN] {
|
|
let syms = names.map(|s| {
|
|
self.reserve(SymInfo {
|
|
name: s.into(),
|
|
external: true,
|
|
})
|
|
});
|
|
self.external.push(External {
|
|
file: file.into(),
|
|
syms: syms.to_vec(),
|
|
});
|
|
syms
|
|
}
|
|
|
|
fn reserve(&mut self, info: SymInfo) -> Symbol {
|
|
let res = Symbol(self.sym_count);
|
|
self.sym_info.push(info);
|
|
self.sym_count += 1;
|
|
res
|
|
}
|
|
|
|
pub fn compile(&self) -> Result<LinkedProgram<A::Addr>, CompilerMsg> {
|
|
A::compile(self)
|
|
}
|
|
|
|
pub fn sym_count(&self) -> usize {
|
|
self.sym_count
|
|
}
|
|
|
|
pub fn sym_info(&self, sym: Symbol) -> &SymInfo {
|
|
&self.sym_info[sym.0]
|
|
}
|
|
}
|
|
|
|
impl<A: Arch> Default for Program<A> {
|
|
fn default() -> Self {
|
|
Self {
|
|
ro_data: Default::default(),
|
|
funcs: Default::default(),
|
|
entry: Default::default(),
|
|
sym_count: Default::default(),
|
|
external: Default::default(),
|
|
sym_info: Default::default(),
|
|
}
|
|
}
|
|
}
|