Files
lang/src/ir/lower/symbol.rs
2025-05-06 23:27:30 -04:00

154 lines
3.9 KiB
Rust

use std::collections::HashMap;
use super::{DataID, FnID, IRLFunction};
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct Symbol(usize);
/// intentionally does not have copy or clone;
/// this should only be consumed once
pub struct WritableSymbol(Symbol);
impl std::ops::Deref for WritableSymbol {
type Target = Symbol;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct SymbolSpace {
ro_data: Vec<(Symbol, Vec<u8>)>,
fns: Vec<(Symbol, IRLFunction)>,
len: usize,
labels: Vec<Option<String>>,
}
pub struct SymbolSpaceBuilder {
symbols: usize,
unwritten_fns: Vec<(WritableSymbol, FnID)>,
fn_map: HashMap<FnID, Symbol>,
data_map: HashMap<DataID, Symbol>,
ro_data: Vec<(Symbol, Vec<u8>)>,
fns: Vec<(Symbol, IRLFunction)>,
labels: Vec<Option<String>>,
}
impl SymbolSpace {
pub fn ro_data(&self) -> &[(Symbol, Vec<u8>)] {
&self.ro_data
}
pub fn fns(&self) -> &[(Symbol, IRLFunction)] {
&self.fns
}
pub fn labels(&self) -> &[Option<String>] {
&self.labels
}
pub fn len(&self) -> usize {
self.len
}
}
impl SymbolSpaceBuilder {
pub fn new() -> Self {
Self {
symbols: 0,
unwritten_fns: Vec::new(),
fn_map: HashMap::new(),
data_map: HashMap::new(),
ro_data: Vec::new(),
fns: Vec::new(),
labels: Vec::new(),
}
}
pub fn with_entries(entries: &[FnID]) -> SymbolSpaceBuilder {
let mut s = Self::new();
for e in entries {
s.func(*e);
}
s
}
pub fn pop_fn(&mut self) -> Option<(WritableSymbol, FnID)> {
self.unwritten_fns.pop()
}
pub fn anon_ro_data(&mut self, data: &[u8], label: Option<String>) -> Symbol {
let sym = self.reserve();
self.write_ro_data(sym, data.to_vec(), label)
}
pub fn ro_data(&mut self, id: DataID, data: &[u8], label: Option<&str>) -> Symbol {
match self.data_map.get(&id) {
Some(s) => *s,
None => {
let sym = self.reserve();
self.data_map.insert(id, *sym);
self.write_ro_data(sym, data.to_vec(), label.map(|l| l.to_string()))
}
}
}
pub fn func(&mut self, id: FnID) -> Symbol {
match self.fn_map.get(&id) {
Some(s) => *s,
None => {
let wsym = self.reserve();
let sym = *wsym;
self.unwritten_fns.push((wsym, id));
self.fn_map.insert(id, sym);
sym
}
}
}
pub fn write_ro_data(
&mut self,
sym: WritableSymbol,
data: Vec<u8>,
name: Option<String>,
) -> Symbol {
self.ro_data.push((*sym, data));
self.labels[sym.0 .0] = name;
*sym
}
pub fn write_fn(
&mut self,
sym: WritableSymbol,
func: IRLFunction,
name: Option<String>,
) -> Symbol {
self.fns.push((*sym, func));
self.labels[sym.0 .0] = name;
*sym
}
pub fn reserve(&mut self) -> WritableSymbol {
let val = self.symbols;
self.symbols += 1;
self.labels.push(None);
WritableSymbol(Symbol(val))
}
pub fn len(&self) -> usize {
self.symbols
}
pub fn finish(self) -> Option<SymbolSpace> {
if self.unwritten_fns.is_empty() {
Some(SymbolSpace {
len: self.symbols,
fns: self.fns,
ro_data: self.ro_data,
labels: self.labels,
})
} else {
None
}
}
}
impl std::fmt::Debug for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "@{}", self.0)
}
}
impl std::ops::Deref for Symbol {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}