@@ 1,434 @@
+use std::{
+ cell::RefCell,
+ collections::HashSet,
+ io,
+ fmt,
+};
+
+use typed_arena::Arena;
+
+// gneral FIXME, do some debug implementing,
+
+#[derive(Default)]
+pub struct ModuleContext<'m> {
+ types: Arena<Typedef<'m>>,
+ data: Arena<Datadef<'m>>,
+ strings: Arena<u8>,
+}
+
+impl<'m> ModuleContext<'m> {
+ pub fn new_module(&'m self, name: &str) -> Module<'m> {
+ let name = self.strings.alloc_str(name);
+ let mut string_table: HashSet<&'m str> = HashSet::new();
+ string_table.insert(name);
+
+ Module {
+ name,
+ ctx: self,
+ string_table: RefCell::new(string_table),
+ types: RefCell::new(Vec::new()),
+ data: RefCell::new(Vec::new()),
+ }
+ }
+
+ pub fn clear(&mut self) {
+ self.types = Default::default();
+ self.strings = Default::default();
+ }
+}
+
+pub struct Module<'m> {
+ name: &'m str,
+ ctx: &'m ModuleContext<'m>,
+ string_table: RefCell<HashSet<&'m str>>,
+ types: RefCell<Vec<&'m Typedef<'m>>>,
+ data: RefCell<Vec<&'m Datadef<'m>>>,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct Symbol<'m>(&'m str);
+
+#[derive(Debug)]
+pub struct Typedef<'m> {
+ name: &'m str,
+ repr: TypeRepr<'m>,
+}
+
+impl fmt::Display for Typedef<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "type :{} = ", self.name)?;
+ match self.repr {
+ TypeRepr::Opaque { align, size } => write!(f, "align {} {{ {} }}", align, size),
+ TypeRepr::Regular { align, ref subtys } => {
+ if let Some(align) = align {
+ write!(f, "align {} ", align)?;
+ }
+ f.write_str("{ ")?;
+
+ for &(ty, n) in subtys {
+ write!(f, "{}", ty)?;
+ if n > 1 {
+ write!(f, " {}, ", n)?;
+ } else {
+ f.write_str(", ")?;
+ }
+ }
+ f.write_str("}")
+ }
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct TypeBuilder<'m> {
+ name: &'m str,
+ pub align: Option<usize>,
+ subtys: Vec<(Type<'m>, usize)>,
+}
+
+impl<'m> TypeBuilder<'m> {
+ pub fn add_subtype<T: Into<Type<'m>>>(&mut self, ty: T) {
+ let ty = ty.into();
+ match self.subtys.last_mut() {
+ Some((last, ref mut n)) if ty == *last => {
+ *n += 1;
+ }
+ _ => self.subtys.push((ty, 1)),
+ }
+ }
+
+ pub fn add_subtype_array<T: Into<Type<'m>>>(&mut self, ty: T, count: usize) {
+ let ty = ty.into();
+ match self.subtys.last_mut() {
+ Some((last, ref mut n)) if ty == *last => {
+ *n += count;
+ }
+ _ => self.subtys.push((ty, count)),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum TypeRepr<'m> {
+ Opaque {
+ align: usize,
+ size: usize,
+ },
+ Regular {
+ align: Option<usize>,
+ subtys: Vec<(Type<'m>, usize)>,
+ },
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Type<'m> {
+ // BASETY
+ Word,
+ Long,
+ Float,
+ Double,
+ // EXTTY
+ Byte,
+ Short,
+ // User Types
+ Typedef(&'m Typedef<'m>),
+}
+
+impl Type<'_> {
+ #[inline]
+ pub fn is_base(&self) -> bool {
+ matches!(self, Self::Word | Self::Long | Self::Float | Self::Double)
+ }
+
+ #[inline]
+ pub fn is_ext(&self) -> bool {
+ self.is_base() || matches!(self, Self::Byte | Self::Short)
+ }
+}
+
+impl fmt::Display for Type<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use Type::*;
+ match self {
+ Word => f.pad("w"),
+ Long => f.pad("l"),
+ Float => f.pad("s"),
+ Double => f.pad("d"),
+ Byte => f.pad("b"),
+ Short => f.pad("h"),
+ Typedef(ty) => write!(f, ":{}", ty.name),
+ }
+ }
+}
+
+impl<'m> From<&'m Typedef<'m>> for Type<'m> {
+ fn from(ty: &'m Typedef<'m>) -> Self {
+ Self::Typedef(ty)
+ }
+}
+
+impl PartialEq for Type<'_> {
+ fn eq(&self, rhs: &Type<'_>) -> bool {
+ use Type::*;
+ match (*self, *rhs) {
+ (Word, Word) => true,
+ (Long, Long) => true,
+ (Double, Double) => true,
+ (Byte, Byte) => true,
+ (Short, Short) => true,
+ (Typedef(tyl), Typedef(tyr)) => std::ptr::eq(tyl, tyr),
+ _ => false,
+ }
+ }
+}
+
+pub struct Datadef<'m> {
+ name: Symbol<'m>,
+ export: bool,
+ m: &'m Module<'m>,
+ pub align: Option<usize>,
+ data: Vec<DataItem<'m>>,
+}
+
+impl<'m> Datadef<'m> {
+ pub fn zeros(&mut self, n: usize) {
+ self.data.push(DataItem::Z(n));
+ }
+
+ pub fn string(&mut self, s: &str) {
+ let s = self.m.intern(s);
+ self.data.push(DataItem::Str(s))
+ }
+
+ pub fn symbol(&mut self, ty: Type<'m>, sym: Symbol<'m>, offset: isize) {
+ assert!(ty.is_ext()); // FIXME this can probably be done in the type system
+ self.data.push(DataItem::Sym(ty, sym, offset));
+ }
+
+ pub fn byte(&mut self, b: u8) {
+ self.data.push(DataItem::Const(Type::Byte, Const::Int(b as i64)));
+ }
+
+ pub fn short(&mut self, n: i16) {
+ self.data.push(DataItem::Const(Type::Short, Const::Int(n as i64)));
+ }
+
+ pub fn long(&mut self, n: i64) {
+ self.data.push(DataItem::Const(Type::Long, Const::Int(n)));
+ }
+
+ pub fn word(&mut self, n: i32) {
+ self.data.push(DataItem::Const(Type::Word, Const::Int(n as i64)));
+ }
+
+ pub fn float(&mut self, f: f32) {
+ self.data.push(DataItem::Const(Type::Float, Const::Float(f)));
+ }
+
+ pub fn double(&mut self, d: f64) {
+ self.data.push(DataItem::Const(Type::Double, Const::Double(d)));
+ }
+}
+
+impl fmt::Display for Datadef<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let vis = if self.export { "export " } else { "" };
+
+ write!(f, "{}data ${} = ", vis, self.name.0)?;
+ if let Some(align) = self.align {
+ write!(f, "align {} ", align)?;
+ }
+
+ f.write_str("{")?;
+ let mut first = true;
+ let mut prev_ty = None;
+ for data in &self.data {
+ if data.ty() == prev_ty && data.ty().is_some() {
+ write!(f, " {:#}", data)?;
+ } else if first {
+ first = false;
+ write!(f, " {}", data)?;
+ } else {
+ write!(f, ", {}", data)?;
+ }
+ prev_ty = data.ty();
+ }
+ f.write_str(" }")
+ }
+}
+
+#[allow(unused)]
+enum DataItem<'m> {
+ Z(usize),
+ Str(&'m str),
+ Sym(Type<'m>, Symbol<'m>, isize),
+ Const(Type<'m>, Const<'m>),
+}
+
+impl<'m> DataItem<'m> {
+ fn ty(&self) -> Option<Type<'m>> {
+ match self {
+ Self::Z(_) => None,
+ Self::Str(_) => Some(Type::Byte),
+ Self::Sym(ty, _, _) | Self::Const(ty, _) => Some(*ty),
+ }
+ }
+
+ fn ty_s(&self) -> &'static str {
+ use Type::*;
+ match self.ty() {
+ Some(Word) => "w ",
+ Some(Long) => "l ",
+ Some(Float) => "s ",
+ Some(Double) => "d ",
+ Some(Byte) => "b ",
+ Some(Short) => "h ",
+ None => "z ",
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl fmt::Display for DataItem<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let ty = if f.alternate() {
+ ""
+ } else {
+ self.ty_s()
+ };
+
+ match self {
+ Self::Z(n) => write!(f, "{}{}", ty, n),
+ Self::Str(s) => write!(f, "{}{:?}", ty, s),
+ Self::Sym(_ty, sym, off) => {
+ if *off != 0 {
+ write!(f, "{}${}+{}", ty, sym.0, off)
+ } else {
+ write!(f, "{}${}", ty, sym.0)
+ }
+ }
+ Self::Const(_ty, constant) => {
+ write!(f, "{}{}", ty, constant)
+ }
+ }
+ }
+}
+
+#[allow(unused)]
+enum Const<'m> {
+ Int(i64),
+ Float(f32),
+ Double(f64),
+ Id(Symbol<'m>),
+}
+
+impl fmt::Display for Const<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::Int(i) => write!(f, "{}", i),
+ Self::Float(s) => write!(f, "s_{}", s),
+ Self::Double(d) => write!(f, "d_{}", d),
+ Self::Id(sym) => write!(f, "${}", sym.0),
+ }
+ }
+}
+
+impl<'m> Module<'m> {
+ pub fn render<W>(&self, mut w: W) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ static VERSION: &'static str = env!("CARGO_PKG_VERSION");
+ write!(
+ &mut w,
+ "## QBE IL generated by cuebee version {}\n\
+ # name: `{}' \n\n",
+ VERSION, self.name
+ )?;
+ for ty in &*self.types.borrow() {
+ writeln!(&mut w, "{}", ty)?;
+ }
+
+ let data = self.data.borrow();
+ if !data.is_empty() {
+ writeln!(&mut w)?;
+ }
+
+ for data in &*data {
+ writeln!(&mut w, "{}", data)?;
+ }
+
+ Ok(())
+ }
+
+ pub fn render_string(&self) -> String {
+ let mut v = Vec::new();
+ self.render(&mut v).expect("writing to vec failed");
+ // We don't emit invalid utf-8
+ unsafe { String::from_utf8_unchecked(v) }
+ }
+
+ fn intern(&self, s: &str) -> &'m str {
+ let mut table = self.string_table.borrow_mut();
+ if let Some(s) = table.get(s) {
+ s
+ } else {
+ let s = self.ctx.strings.alloc_str(s);
+ table.insert(s);
+ s
+ }
+ }
+
+ fn gensym(&self, s: &str) -> Symbol<'m> {
+ Symbol(self.intern(s))
+ }
+
+ pub fn opaque_type(&self, name: &str, align: usize, size: usize) -> &Typedef {
+ let name = self.intern(name);
+ let ty = self.ctx.types.alloc(Typedef {
+ name,
+ repr: TypeRepr::Opaque { align, size },
+ });
+ self.types.borrow_mut().push(ty);
+ ty
+ }
+
+ pub fn new_type(&self, name: &str) -> TypeBuilder<'m> {
+ let name = self.intern(name);
+ TypeBuilder {
+ name,
+ align: None,
+ subtys: Vec::new(),
+ }
+ }
+
+ pub fn add_type(&self, tb: TypeBuilder<'m>) -> &Typedef {
+ let TypeBuilder { name, align, subtys } = tb;
+ let ty = self.ctx.types.alloc(Typedef {
+ name,
+ repr: TypeRepr::Regular {
+ align,
+ subtys,
+ }
+ });
+ self.types.borrow_mut().push(ty);
+ ty
+ }
+
+ pub fn new_data(&self, name: &str) -> (&'m mut Datadef, Symbol<'m>) {
+ let name = self.gensym(name);
+ let data = self.ctx.data.alloc(Datadef {
+ name,
+ m: &self,
+ align: None,
+ export: false,
+ data: Vec::new(),
+ });
+ (data, name)
+ }
+
+ pub fn add_data(&self, data: &'m Datadef<'m>) -> &'m Datadef {
+ self.data.borrow_mut().push(data);
+ data
+ }
+}