From 1df5429eab671f388a54a55ce0abe58b1df6cbcf Mon Sep 17 00:00:00 2001
From: Janis <janis@nirgendwo.xyz>
Date: Sun, 22 Dec 2024 18:57:19 +0100
Subject: [PATCH] extracting ast2::intern into its own file

---
 src/ast2/intern.rs | 1140 ++++++++++++++++++++++++++++++++++++++++++++
 src/ast2/mod.rs    | 1081 +----------------------------------------
 2 files changed, 1143 insertions(+), 1078 deletions(-)
 create mode 100644 src/ast2/intern.rs

diff --git a/src/ast2/intern.rs b/src/ast2/intern.rs
new file mode 100644
index 0000000..c6528d6
--- /dev/null
+++ b/src/ast2/intern.rs
@@ -0,0 +1,1140 @@
+use std::{
+    collections::BTreeMap,
+    fmt::Display,
+    hash::{Hash, Hasher},
+};
+
+use num_bigint::{BigInt, BigUint, Sign};
+
+use crate::{
+    ast::IntegralType,
+    common::{from_lo_hi_dwords, into_lo_hi_dwords},
+    variant,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[repr(u8)]
+pub enum SimpleType {
+    F32 = 0,
+    F64,
+    Bool,
+    Void,
+    USize,
+    ISize,
+    ComptimeInt,
+}
+
+impl From<u8> for SimpleType {
+    fn from(value: u8) -> Self {
+        match value {
+            0 => Self::F32,
+            1 => Self::F64,
+            2 => Self::Bool,
+            3 => Self::Void,
+            4 => Self::USize,
+            5 => Self::ISize,
+            6 => Self::ComptimeInt,
+            _ => panic!("{value} is not a simple type"),
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Tag {
+    String,
+    SIntSmall,
+    UIntSmall,
+    TrueValue,
+    FalseValue,
+    UInt64,
+    SInt64,
+    F32,
+    F64,
+    PositiveInt,
+    NegativeInt,
+    UIntType,
+    SIntType,
+    SimpleType,
+    PointerType,
+    ArrayType,
+    FunctionType,
+    StructType,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+struct Item {
+    tag: Tag,
+    index: u32,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+#[non_exhaustive]
+pub enum Key<'a> {
+    String {
+        str: &'a str,
+    },
+    SIntSmall {
+        bits: i32,
+    },
+    UIntSmall {
+        bits: u32,
+    },
+    SInt64 {
+        bits: i64,
+    },
+    UInt64 {
+        bits: u64,
+    },
+    F32 {
+        bits: f32,
+    },
+    F64 {
+        bits: f64,
+    },
+    PositiveInt {
+        bigint: BigInt,
+    },
+    NegativeInt {
+        bigint: BigInt,
+    },
+    UIntType {
+        bits: u16,
+    },
+    SIntType {
+        bits: u16,
+    },
+    SimpleType {
+        ty: SimpleType,
+    },
+    PointerType {
+        pointee: Index,
+        flags: PointerFlags,
+    },
+    ArrayType {
+        pointee: Index,
+        flags: PointerFlags,
+        length: u32,
+    },
+    FunctionType {
+        return_type: Index,
+        parameters: Vec<Index>,
+    },
+    StructType {
+        decl: super::Index,
+        name: Index,
+        packed: bool,
+        c_like: bool,
+        /// vec of (Name, Type)
+        fields: Vec<(Index, Index)>,
+    },
+    TrueValue,
+    FalseValue,
+}
+
+impl Hash for Key<'_> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        core::mem::discriminant(self).hash(state);
+        match self {
+            Key::String { str } => str.hash(state),
+            Key::SIntSmall { bits } => bits.hash(state),
+            Key::UIntSmall { bits } => bits.hash(state),
+            Key::SInt64 { bits } => bits.hash(state),
+            Key::UInt64 { bits } => bits.hash(state),
+            Key::F32 { bits } => ordered_float::OrderedFloat(*bits).hash(state),
+            Key::F64 { bits } => ordered_float::OrderedFloat(*bits).hash(state),
+            Key::PositiveInt { bigint } => bigint.hash(state),
+            Key::NegativeInt { bigint } => bigint.hash(state),
+            Key::UIntType { bits } => bits.hash(state),
+            Key::SIntType { bits } => bits.hash(state),
+            Key::SimpleType { ty } => ty.hash(state),
+            Key::PointerType { pointee, flags } => (pointee, flags).hash(state),
+            Key::ArrayType {
+                pointee,
+                flags,
+                length,
+            } => (*pointee, *flags, *length).hash(state),
+            Key::StructType { name, decl, .. } => (*name, *decl).hash(state),
+            Key::FunctionType {
+                return_type,
+                parameters,
+            } => (return_type, parameters).hash(state),
+            Key::TrueValue | Key::FalseValue => {}
+        }
+    }
+}
+
+// #[repr(packed)]
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct PointerFlags {
+    pub volatile: bool,
+    pub is_const: bool,
+    pub noalias: bool,
+}
+
+impl PointerFlags {
+    pub fn new(is_const: bool, volatile: bool, noalias: bool) -> Self {
+        Self {
+            is_const,
+            volatile,
+            noalias,
+        }
+    }
+
+    pub fn pack(self) -> u8 {
+        (self.volatile as u8) << 0
+            | (self.is_const as u8) << 1
+            | (self.noalias as u8) << 2
+    }
+    pub fn unpack(packed: u8) -> Self {
+        Self {
+            volatile: packed & (1 << 0) != 0,
+            is_const: packed & (1 << 1) != 0,
+            noalias: packed & (1 << 2) != 0,
+        }
+    }
+}
+
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct StructFlags {
+    pub packed: bool,
+    pub c_like: bool,
+    pub num_fields: u32,
+}
+
+impl StructFlags {
+    const MASK: u32 = (1u32 << 30) - 1;
+    pub fn new(packed: bool, c_like: bool, num_fields: u32) -> Self {
+        assert!(num_fields < (1 << 30));
+        Self {
+            packed,
+            c_like,
+            num_fields,
+        }
+    }
+    pub fn pack(self) -> u32 {
+        assert!(self.num_fields < (1 << 30));
+        (self.packed as u32) << 31
+            | (self.c_like as u32) << 30
+            | self.num_fields & Self::MASK
+    }
+    pub fn unpack(packed: u32) -> Self {
+        Self {
+            packed: packed & (1 << 31) != 0,
+            c_like: packed & (1 << 30) != 0,
+            num_fields: packed & Self::MASK,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+struct FunctionInfo {
+    void_return: bool,
+    num_params: u32,
+}
+impl FunctionInfo {
+    fn new(void_return: bool, num_params: u32) -> Self {
+        Self {
+            void_return,
+            num_params,
+        }
+    }
+
+    const MASK: u32 = 1u32 << (u32::BITS - 1);
+    fn pack(self) -> u32 {
+        (self.void_return as u32 * Self::MASK) | self.num_params & !Self::MASK
+    }
+    fn unpack(packed: u32) -> Self {
+        Self {
+            void_return: packed & Self::MASK != 0,
+            num_params: packed & !Self::MASK,
+        }
+    }
+    fn len(self) -> u32 {
+        self.void_return as u32 + self.num_params
+    }
+}
+
+impl Item {
+    fn idx(self) -> usize {
+        self.index as usize
+    }
+}
+
+#[repr(transparent)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Index(pub u32);
+
+impl Display for Index {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "#{}", self.0)
+    }
+}
+
+impl Index {
+    pub fn into_u32(self) -> u32 {
+        unsafe { core::mem::transmute(self) }
+    }
+    pub fn as_u32(&self) -> &u32 {
+        unsafe { core::mem::transmute(self) }
+    }
+    fn index(&self) -> usize {
+        self.0 as usize
+    }
+
+    pub fn is_valid(&self) -> bool {
+        self.0 != u32::MAX
+    }
+
+    pub fn invalid() -> Self {
+        Self(u32::MAX)
+    }
+}
+
+pub struct InternPool {
+    tags: Vec<Tag>,
+    indices: Vec<u32>,
+    //
+    strings: Vec<u8>,
+    words: Vec<u32>,
+    hashed: BTreeMap<u64, Index>,
+}
+
+impl std::fmt::Debug for InternPool {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("InternPool")
+            .field_with("keys", |f| {
+                let mut list = f.debug_list();
+
+                let keys = (0..self.indices.len())
+                    .map(|i| Index(i as u32))
+                    .map(|idx| (idx, self.get_key(idx)));
+                for (idx, key) in keys {
+                    list.entry_with(|f| write!(f, "{}: {key:?}", idx.0));
+                }
+
+                list.finish()
+            })
+            .field_with("hashed", |f| {
+                let mut list = f.debug_list();
+                for (hash, idx) in self.hashed.iter() {
+                    list.entry_with(|f| write!(f, "{hash}: {}", idx.0));
+                }
+                list.finish()
+            })
+            .finish_non_exhaustive()
+    }
+}
+
+const STATIC_KEYS: [Key; 21] = [
+    Key::SimpleType {
+        ty: SimpleType::Bool,
+    },
+    Key::SimpleType {
+        ty: SimpleType::F32,
+    },
+    Key::SimpleType {
+        ty: SimpleType::F64,
+    },
+    Key::SimpleType {
+        ty: SimpleType::USize,
+    },
+    Key::SimpleType {
+        ty: SimpleType::ISize,
+    },
+    Key::SimpleType {
+        ty: SimpleType::Void,
+    },
+    Key::SimpleType {
+        ty: SimpleType::ComptimeInt,
+    },
+    Key::SIntType { bits: 1 },
+    Key::UIntType { bits: 1 },
+    Key::SIntType { bits: 0 },
+    Key::UIntType { bits: 0 },
+    Key::SIntType { bits: 8 },
+    Key::UIntType { bits: 8 },
+    Key::SIntType { bits: 16 },
+    Key::UIntType { bits: 16 },
+    Key::SIntType { bits: 32 },
+    Key::UIntType { bits: 32 },
+    Key::SIntType { bits: 64 },
+    Key::UIntType { bits: 64 },
+    Key::TrueValue,
+    Key::FalseValue,
+];
+
+impl InternPool {
+    pub fn get_void_type(&self) -> Index {
+        self.get_assume_present(&Key::SimpleType {
+            ty: SimpleType::Void,
+        })
+    }
+    pub fn get_bool_type(&self) -> Index {
+        self.get_assume_present(&Key::SimpleType {
+            ty: SimpleType::Bool,
+        })
+    }
+    pub fn get_true_value(&self) -> Index {
+        self.get_assume_present(&Key::TrueValue)
+    }
+    pub fn get_false_value(&self) -> Index {
+        self.get_assume_present(&Key::FalseValue)
+    }
+    pub fn get_f32_type(&self) -> Index {
+        self.get_assume_present(&Key::SimpleType {
+            ty: SimpleType::F32,
+        })
+    }
+    pub fn get_f64_type(&self) -> Index {
+        self.get_assume_present(&Key::SimpleType {
+            ty: SimpleType::F64,
+        })
+    }
+    pub fn get_comptime_int_type(&self) -> Index {
+        self.get_assume_present(&Key::SimpleType {
+            ty: SimpleType::ComptimeInt,
+        })
+    }
+    pub fn get_usize_type(&self) -> Index {
+        self.get_assume_present(&Key::SimpleType {
+            ty: SimpleType::USize,
+        })
+    }
+    pub fn get_isize_type(&self) -> Index {
+        self.get_assume_present(&Key::SimpleType {
+            ty: SimpleType::ISize,
+        })
+    }
+    pub fn get_u0_type(&self) -> Index {
+        self.get_assume_present(&Key::UIntType { bits: 0 })
+    }
+    pub fn get_i0_type(&self) -> Index {
+        self.get_assume_present(&Key::SIntType { bits: 0 })
+    }
+    pub fn get_u1_type(&self) -> Index {
+        self.get_assume_present(&Key::UIntType { bits: 1 })
+    }
+    pub fn get_i1_type(&self) -> Index {
+        self.get_assume_present(&Key::SIntType { bits: 1 })
+    }
+    pub fn get_u8_type(&self) -> Index {
+        self.get_assume_present(&Key::UIntType { bits: 8 })
+    }
+    pub fn get_i8_type(&self) -> Index {
+        self.get_assume_present(&Key::SIntType { bits: 8 })
+    }
+    pub fn get_u16_type(&self) -> Index {
+        self.get_assume_present(&Key::UIntType { bits: 16 })
+    }
+    pub fn get_i16_type(&self) -> Index {
+        self.get_assume_present(&Key::SIntType { bits: 16 })
+    }
+    pub fn get_u32_type(&self) -> Index {
+        self.get_assume_present(&Key::UIntType { bits: 32 })
+    }
+    pub fn get_i32_type(&self) -> Index {
+        self.get_assume_present(&Key::SIntType { bits: 32 })
+    }
+    pub fn get_u64_type(&self) -> Index {
+        self.get_assume_present(&Key::UIntType { bits: 64 })
+    }
+    pub fn get_i64_type(&self) -> Index {
+        self.get_assume_present(&Key::SIntType { bits: 64 })
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct TypeInfo {
+    pub bitsize: u32,
+    pub bitalign: u32,
+}
+
+impl InternPool {
+    pub fn size_of_type(&self, index: Index, ptr_size: TypeInfo) -> TypeInfo {
+        match self.get_key(index) {
+            Key::UIntType { bits } => {
+                let bits = bits as u32;
+                TypeInfo {
+                    bitsize: bits,
+                    bitalign: bits.next_multiple_of(8).next_power_of_two(),
+                }
+            }
+            Key::SIntType { bits } => {
+                let bits = bits as u32;
+                TypeInfo {
+                    bitsize: bits,
+                    bitalign: bits.next_multiple_of(8).next_power_of_two(),
+                }
+            }
+            Key::SimpleType { ty } => match ty {
+                SimpleType::F32 => TypeInfo {
+                    bitsize: 32,
+                    bitalign: 32,
+                },
+                SimpleType::F64 => TypeInfo {
+                    bitsize: 64,
+                    bitalign: 64,
+                },
+                SimpleType::Bool => TypeInfo {
+                    bitsize: 1,
+                    bitalign: 1,
+                },
+                SimpleType::Void => TypeInfo {
+                    bitsize: 0,
+                    bitalign: 0,
+                },
+                SimpleType::USize => ptr_size,
+                SimpleType::ISize => ptr_size,
+                SimpleType::ComptimeInt => panic!("comptime int is unsized"),
+            },
+            Key::PointerType { .. } => ptr_size,
+            Key::ArrayType {
+                pointee, length, ..
+            } => {
+                let element_size = self.size_of_type(pointee, ptr_size);
+                let bitsize = element_size.bitalign * length;
+                TypeInfo {
+                    bitsize,
+                    ..element_size
+                }
+            }
+            Key::FunctionType { .. } => ptr_size,
+            Key::StructType { packed, fields, .. } => {
+                // TODO: c-like layout
+                let (size, align) =
+                    fields.iter().fold((0, 0), |(size, align), (_name, ty)| {
+                        let field_size = self.size_of_type(*ty, ptr_size);
+                        let size = size + field_size.bitsize;
+
+                        let size = if packed {
+                            size.next_multiple_of(field_size.bitalign)
+                        } else {
+                            size
+                        };
+                        let align = align.max(field_size.bitalign);
+                        (size, align)
+                    });
+
+                TypeInfo {
+                    bitsize: size,
+                    bitalign: align,
+                }
+            }
+            _ => {
+                panic!("index was not a type")
+            }
+        }
+    }
+
+    pub fn from_ast1_type(
+        &self,
+        pointer_bits: u16,
+        ty: &crate::ast::Type,
+    ) -> Index {
+        match ty {
+            crate::ast::Type::Bool => self.get_bool_type(),
+            crate::ast::Type::ComptimeNumber => self.get_comptime_int_type(),
+            crate::ast::Type::Integer(i) => self.get_assume_present(&{
+                if i.signed {
+                    Key::SIntType { bits: i.bits }
+                } else {
+                    Key::UIntType { bits: i.bits }
+                }
+            }),
+            crate::ast::Type::Floating(crate::ast::FloatingType::Binary32) => {
+                self.get_f32_type()
+            }
+            crate::ast::Type::Floating(crate::ast::FloatingType::Binary64) => {
+                self.get_f64_type()
+            }
+            crate::ast::Type::Pointer { constness, pointee } => self
+                .get_assume_present(&Key::PointerType {
+                    pointee: self.from_ast1_type(pointer_bits, &pointee),
+                    flags: PointerFlags::new(*constness, false, false),
+                }),
+            crate::ast::Type::Fn { .. } => {
+                unimplemented!()
+            }
+            _ => {
+                todo!()
+            }
+        }
+    }
+
+    pub fn as_ast1_type(
+        &self,
+        pointer_bits: u16,
+        index: Index,
+    ) -> crate::ast::Type {
+        use crate::ast::Type;
+        match self.get_key(index) {
+            Key::UIntType { bits } => {
+                Type::Integer(IntegralType::new(false, bits))
+            }
+            Key::SIntType { bits } => {
+                Type::Integer(IntegralType::new(true, bits))
+            }
+            Key::SimpleType { ty } => match ty {
+                SimpleType::F32 => {
+                    Type::Floating(crate::ast::FloatingType::Binary32)
+                }
+                SimpleType::F64 => {
+                    Type::Floating(crate::ast::FloatingType::Binary64)
+                }
+                SimpleType::Bool => Type::Bool,
+                SimpleType::Void => Type::Void,
+                SimpleType::USize => {
+                    Type::Integer(IntegralType::new(false, pointer_bits))
+                }
+                SimpleType::ISize => {
+                    Type::Integer(IntegralType::new(true, pointer_bits))
+                }
+                SimpleType::ComptimeInt => Type::comptime_number(),
+            },
+            Key::PointerType { pointee, flags } => Type::Pointer {
+                constness: flags.is_const,
+                pointee: Box::new(self.as_ast1_type(pointer_bits, pointee)),
+            },
+            Key::FunctionType {
+                return_type,
+                parameters,
+            } => Type::Fn {
+                parameter_types: parameters
+                    .into_iter()
+                    .map(|i| self.as_ast1_type(pointer_bits, i))
+                    .collect(),
+                return_type: Box::new(
+                    self.as_ast1_type(pointer_bits, return_type),
+                ),
+            },
+            _ => unimplemented!(),
+        }
+    }
+}
+
+pub const AMD64_POINTER_BITS: u16 = 64;
+
+impl InternPool {
+    pub fn create() -> Self {
+        let mut this = Self {
+            tags: Vec::new(),
+            indices: Vec::new(),
+            strings: Vec::new(),
+            words: Vec::new(),
+            hashed: BTreeMap::new(),
+        };
+
+        this.extend_keys(STATIC_KEYS);
+
+        this
+    }
+
+    fn extend_keys<'a, K: IntoIterator<Item = Key<'a>>>(&mut self, keys: K) {
+        for k in keys.into_iter() {
+            let mut hasher = std::hash::DefaultHasher::new();
+            k.hash(&mut hasher);
+            let digest = hasher.finish();
+            let i = self.insert(k);
+            self.hashed.insert(digest, i);
+        }
+    }
+
+    fn len(&self) -> u32 {
+        u32::try_from(self.tags.len())
+            .expect(&format!("more than {} items in internpool!", u32::MAX))
+    }
+
+    pub fn get_or_insert(&mut self, key: Key) -> Index {
+        let mut hasher = std::hash::DefaultHasher::new();
+        key.hash(&mut hasher);
+        let digest = hasher.finish();
+        if let Some(&idx) = self.hashed.get(&digest) {
+            idx
+        } else {
+            let i = self.insert(key);
+            self.hashed.insert(digest, i);
+            i
+        }
+    }
+
+    fn insert(&mut self, key: Key) -> Index {
+        match key {
+            Key::String { str } => {
+                let len = str.len() as u32;
+                let start = self.extend_strings(str);
+
+                let words_idx = self.extend_words([start, len]);
+                self.create_item(Tag::String, words_idx)
+            }
+            Key::SIntSmall { bits } => {
+                self.create_item(Tag::SIntSmall, bits as u32)
+            }
+            Key::UIntSmall { bits } => {
+                self.create_item(Tag::UIntSmall, bits as u32)
+            }
+            Key::F32 { bits } => self.create_item(Tag::F32, bits as u32),
+            Key::F64 { bits } => {
+                let (lo, hi) = into_lo_hi_dwords(bits as u64);
+                let words_idx = self.extend_words([lo, hi]);
+                self.create_item(Tag::F64, words_idx)
+            }
+            Key::SInt64 { bits } => {
+                let (lo, hi) = into_lo_hi_dwords(bits as u64);
+                let i = self.extend_words([lo, hi]);
+                self.create_item(Tag::SInt64, i)
+            }
+            Key::UInt64 { bits } => {
+                let (lo, hi) = into_lo_hi_dwords(bits as u64);
+                let i = self.extend_words([lo, hi]);
+                self.create_item(Tag::UInt64, i)
+            }
+            Key::PositiveInt { bigint } => {
+                let (_, words) = bigint.to_u32_digits();
+                let i = self.push_word(words.len() as u32);
+                _ = self.extend_words(words);
+                self.create_item(Tag::PositiveInt, i)
+            }
+            Key::NegativeInt { bigint } => {
+                let (_, words) = bigint.to_u32_digits();
+                let i = self.push_word(words.len() as u32);
+                _ = self.extend_words(words);
+                self.create_item(Tag::NegativeInt, i)
+            }
+
+            Key::UIntType { bits } => {
+                self.create_item(Tag::UIntType, bits as u32)
+            }
+            Key::SIntType { bits } => {
+                self.create_item(Tag::SIntType, bits as u32)
+            }
+            Key::SimpleType { ty } => {
+                self.create_item(Tag::SimpleType, ty as u8 as u32)
+            }
+            Key::PointerType { pointee, flags } => {
+                let flags = flags.pack();
+                let i = self.extend_words([pointee.0, flags as u32]);
+                self.create_item(Tag::PointerType, i)
+            }
+            Key::ArrayType {
+                pointee,
+                flags,
+                length,
+            } => {
+                let flags = flags.pack();
+                let i = self.extend_words([pointee.0, flags as u32, length]);
+                self.create_item(Tag::ArrayType, i)
+            }
+            Key::StructType {
+                name,
+                decl,
+                packed,
+                c_like,
+                fields,
+            } => {
+                let flags =
+                    StructFlags::new(packed, c_like, fields.len() as u32)
+                        .pack();
+                let i = self.extend_words([
+                    name.into_u32(),
+                    decl.into_u32(),
+                    flags,
+                    u32::MAX,
+                ]);
+                if !fields.is_empty() {
+                    let fields_offset = self.extend_words(
+                        fields
+                            .into_iter()
+                            .map(|(n, t)| [n.into_u32(), t.into_u32()])
+                            .flatten(),
+                    );
+                    self.words[i as usize + 3] = fields_offset;
+                }
+                self.create_item(Tag::StructType, i)
+            }
+            Key::FunctionType {
+                return_type,
+                parameters,
+            } => {
+                let info = FunctionInfo::new(
+                    return_type == self.get_simple_type(SimpleType::Void),
+                    parameters.len() as u32,
+                );
+
+                let start = self.push_word(info.pack());
+                self.extend_words([return_type.into_u32()]);
+                _ = self.extend_words(parameters.into_iter().map(|i| i.0));
+
+                self.create_item(Tag::FunctionType, start)
+            }
+            Key::TrueValue => self.create_item(Tag::TrueValue, 0),
+            Key::FalseValue => self.create_item(Tag::FalseValue, 0),
+        }
+    }
+
+    fn extend_strings<B: AsRef<[u8]>>(&mut self, b: B) -> u32 {
+        let idx = self.strings.len() as u32;
+        self.strings.extend(b.as_ref());
+        idx
+    }
+    fn extend_words<I: IntoIterator<Item = u32>>(&mut self, i: I) -> u32 {
+        let idx = self.words.len() as u32;
+        self.words.extend(i);
+        idx
+    }
+    fn push_word(&mut self, word: u32) -> u32 {
+        let idx = self.words.len() as u32;
+        self.words.push(word);
+        idx
+    }
+
+    fn create_item(&mut self, tag: Tag, index: u32) -> Index {
+        let len = self.len();
+        self.tags.push(tag);
+        self.indices.push(index);
+        Index(len)
+    }
+
+    pub fn get_key(&self, index: Index) -> Key {
+        let item = self.get_item(index).unwrap();
+        match item.tag {
+            Tag::String => {
+                let start = self.words[item.idx()];
+                let len = self.words[item.idx() + 1];
+                let str = unsafe {
+                    core::str::from_utf8_unchecked(
+                        &self.strings[start as usize..][..len as usize],
+                    )
+                };
+                Key::String { str }
+            }
+            Tag::UIntSmall => Key::UIntSmall {
+                bits: item.index as u32,
+            },
+            Tag::SIntSmall => Key::SIntSmall {
+                bits: item.index as i32,
+            },
+            Tag::F32 => Key::F32 {
+                bits: f32::from_le_bytes(item.index.to_le_bytes()),
+            },
+            Tag::F64 => {
+                let idx = item.idx();
+                let bits =
+                    from_lo_hi_dwords(self.words[idx], self.words[idx + 1]);
+                Key::F64 {
+                    bits: f64::from_le_bytes(bits.to_le_bytes()),
+                }
+            }
+            Tag::SInt64 => {
+                let bits = from_lo_hi_dwords(
+                    self.words[item.idx()],
+                    self.words[item.idx() + 1],
+                ) as i64;
+                Key::SInt64 { bits }
+            }
+            Tag::UInt64 => {
+                let bits = from_lo_hi_dwords(
+                    self.words[item.idx()],
+                    self.words[item.idx() + 1],
+                );
+                Key::UInt64 { bits }
+            }
+            Tag::NegativeInt => {
+                let len = self.words[item.idx()];
+                let start = item.idx() + 1;
+                let end = start + len as usize;
+                let data = BigUint::from_slice(&self.words[start..end]);
+                let bigint = BigInt::from_biguint(Sign::Minus, data);
+                Key::NegativeInt { bigint }
+            }
+            Tag::PositiveInt => {
+                let len = self.words[item.idx()];
+                let start = item.idx() + 1;
+                let end = start + len as usize;
+                let data = BigUint::from_slice(&self.words[start..end]);
+                let bigint = BigInt::from_biguint(Sign::Plus, data);
+                Key::PositiveInt { bigint }
+            }
+            Tag::SIntType => Key::SIntType {
+                bits: item.index as u16,
+            },
+            Tag::UIntType => Key::UIntType {
+                bits: item.index as u16,
+            },
+            Tag::SimpleType => {
+                let ty = item.idx() as u8;
+
+                Key::SimpleType {
+                    ty: unsafe { core::mem::transmute::<u8, SimpleType>(ty) },
+                }
+            }
+            Tag::PointerType => {
+                let pointee = Index(self.words[item.idx()]);
+                let flags =
+                    PointerFlags::unpack(self.words[item.idx() + 1] as u8);
+
+                Key::PointerType { pointee, flags }
+            }
+            Tag::ArrayType => {
+                let pointee = Index(self.words[item.idx()]);
+                let flags =
+                    PointerFlags::unpack(self.words[item.idx() + 1] as u8);
+                let length = self.words[item.idx() + 2];
+
+                Key::ArrayType {
+                    pointee,
+                    flags,
+                    length,
+                }
+            }
+            Tag::StructType => {
+                let name = Index(self.words[item.idx()]);
+                let decl = super::Index::new(self.words[item.idx() + 1]);
+                let flags = StructFlags::unpack(self.words[item.idx() + 2]);
+                let fields = if flags.num_fields != 0 {
+                    let fields_offset = self.words[item.idx() + 3] as usize;
+                    let fields_end =
+                        fields_offset + flags.num_fields as usize * 2;
+
+                    self.words[fields_offset..fields_end]
+                        .iter()
+                        .cloned()
+                        .array_chunks::<2>()
+                        .map(|[n, t]| (Index(n), Index(t)))
+                        .collect::<Vec<_>>()
+                } else {
+                    vec![]
+                };
+
+                Key::StructType {
+                    name,
+                    decl,
+                    packed: flags.packed,
+                    c_like: flags.c_like,
+                    fields,
+                }
+            }
+            Tag::FunctionType => {
+                let info = FunctionInfo::unpack(self.words[item.idx()]);
+                let len = info.len();
+                let (return_type, parameters) = if info.void_return {
+                    let start = item.idx() + 1;
+                    let end = start + len as usize;
+                    let params = self.words[start..end]
+                        .iter()
+                        .map(|&i| Index(i))
+                        .collect::<Vec<_>>();
+                    (
+                        self.get_assume_present(&Key::SimpleType {
+                            ty: SimpleType::Void,
+                        }),
+                        params,
+                    )
+                } else {
+                    let return_type = Index(self.words[item.idx() + 1]);
+                    let start = item.idx() + 2;
+                    let end = start + len as usize;
+                    let params = self.words[start..end]
+                        .iter()
+                        .map(|&i| Index(i))
+                        .collect::<Vec<_>>();
+                    (return_type, params)
+                };
+
+                Key::FunctionType {
+                    return_type,
+                    parameters,
+                }
+            }
+            Tag::TrueValue => Key::TrueValue,
+            Tag::FalseValue => Key::FalseValue,
+        }
+    }
+
+    pub fn try_get_index(&self, key: &Key) -> Option<Index> {
+        let mut hasher = std::hash::DefaultHasher::new();
+        key.hash(&mut hasher);
+        let digest = hasher.finish();
+        self.hashed.get(&digest).cloned()
+    }
+
+    pub fn get_assume_present(&self, key: &Key) -> Index {
+        self.try_get_index(&key)
+            .expect(&format!("key {key:?} not present in pool."))
+    }
+
+    pub fn get_int_type(&mut self, signed: bool, bits: u16) -> Index {
+        let key = match signed {
+            true => Key::SIntType { bits },
+            false => Key::UIntType { bits },
+        };
+
+        self.get_or_insert(key)
+    }
+
+    pub fn get_string_index(&mut self, str: &str) -> Index {
+        self.get_or_insert(Key::String { str })
+    }
+    pub fn try_get_string_index(&self, str: &str) -> Option<Index> {
+        self.try_get_index(&Key::String { str })
+    }
+
+    pub fn get_simple_type(&mut self, ty: SimpleType) -> Index {
+        self.get_or_insert(Key::SimpleType { ty })
+    }
+    pub fn try_get_simple_type(&self, ty: SimpleType) -> Option<Index> {
+        self.try_get_index(&Key::SimpleType { ty })
+    }
+
+    pub fn get_function_type<P: IntoIterator<Item = Index>>(
+        &mut self,
+        return_type: Index,
+        parameters: P,
+    ) -> Index {
+        self.get_or_insert(Key::FunctionType {
+            return_type,
+            parameters: parameters.into_iter().collect(),
+        })
+    }
+
+    pub fn try_get_function_type<P: IntoIterator<Item = Index>>(
+        &self,
+        return_type: Index,
+        parameters: P,
+    ) -> Option<Index> {
+        self.try_get_index(&Key::FunctionType {
+            return_type,
+            parameters: parameters.into_iter().collect(),
+        })
+    }
+
+    pub fn get_pointer_type(
+        &mut self,
+        pointee: Index,
+        flags: Option<PointerFlags>,
+    ) -> Index {
+        let key = Key::PointerType {
+            pointee,
+            flags: flags.unwrap_or_default(),
+        };
+        self.get_or_insert(key)
+    }
+    pub fn try_get_pointer_type(
+        &self,
+        pointee: Index,
+        flags: Option<PointerFlags>,
+    ) -> Option<Index> {
+        self.try_get_index(
+            &(Key::PointerType {
+                pointee,
+                flags: flags.unwrap_or_default(),
+            }),
+        )
+    }
+
+    pub fn insert_or_replace_struct_type<
+        I: IntoIterator<Item = (Index, Index)>,
+    >(
+        &mut self,
+        name: Index,
+        decl: super::Index,
+        packed: bool,
+        c_like: bool,
+        fields: I,
+    ) -> Index {
+        let key = Key::StructType {
+            name,
+            decl,
+            packed,
+            c_like,
+            fields: vec![],
+        };
+        if let Some(i) = self.try_get_index(&key).and_then(|i| self.get_item(i))
+        {
+            let fields_offset = self.extend_words(
+                fields
+                    .into_iter()
+                    .map(|(n, t)| [n.into_u32(), t.into_u32()])
+                    .flatten(),
+            );
+            self.words[i.idx() + 3] = fields_offset;
+            let fields_end = self.words.len() as u32;
+            let num_fields = (fields_end - fields_offset) / 2;
+            let flags = StructFlags::new(packed, c_like, num_fields).pack();
+            self.words[i.idx() + 2] = flags;
+        }
+        self.get_or_insert(key)
+    }
+
+    pub fn get_struct_type(
+        &mut self,
+        name: Index,
+        decl: super::Index,
+    ) -> Index {
+        let key = Key::StructType {
+            name,
+            decl,
+            packed: false,
+            c_like: false,
+            fields: vec![],
+        };
+        self.get_or_insert(key)
+    }
+    pub fn try_get_struct_type(
+        &self,
+        name: Index,
+        decl: super::Index,
+    ) -> Option<Index> {
+        self.try_get_index(&Key::StructType {
+            name,
+            decl,
+            packed: false,
+            c_like: false,
+            fields: vec![],
+        })
+    }
+
+    pub fn get_array_type(
+        &mut self,
+        pointee: Index,
+        flags: Option<PointerFlags>,
+        length: u32,
+    ) -> Index {
+        let key = Key::ArrayType {
+            pointee,
+            flags: flags.unwrap_or_default(),
+            length,
+        };
+        self.get_or_insert(key)
+    }
+    pub fn try_get_array_type(
+        &self,
+        pointee: Index,
+        flags: Option<PointerFlags>,
+        length: u32,
+    ) -> Option<Index> {
+        self.try_get_index(&Key::ArrayType {
+            pointee,
+            flags: flags.unwrap_or_default(),
+            length,
+        })
+    }
+
+    pub fn get_str(&self, index: Index) -> &str {
+        let key = self.get_key(index);
+        assert!(matches!(key, Key::String { .. }));
+        variant!(key => Key::String { str });
+
+        str
+    }
+
+    fn check_bounds(&self, index: Index) -> Option<Index> {
+        (index.0 < self.len()).then_some(index)
+    }
+
+    fn get_item(&self, index: Index) -> Option<Item> {
+        self.check_bounds(index).map(|i| Item {
+            tag: self.tags[i.index()],
+            index: self.indices[i.index()],
+        })
+    }
+}
diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs
index 191cad5..a1da2e8 100644
--- a/src/ast2/mod.rs
+++ b/src/ast2/mod.rs
@@ -10,1086 +10,11 @@ use intern::{InternPool, PointerFlags, StructFlags};
 use num_bigint::BigInt;
 
 use crate::{
-    ast::FloatingType, comptime::ComptimeNumber, lexer::SourceLocation, tokens::Token,
-    writeln_indented,
+    ast::FloatingType, comptime::ComptimeNumber, lexer::SourceLocation,
+    tokens::Token, writeln_indented,
 };
 
-pub mod intern {
-    use std::{
-        collections::BTreeMap,
-        fmt::Display,
-        hash::{Hash, Hasher},
-    };
-
-    use num_bigint::{BigInt, BigUint, Sign};
-
-    use crate::{
-        ast::IntegralType,
-        common::{from_lo_hi_dwords, into_lo_hi_dwords},
-        variant,
-    };
-
-    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-    #[repr(u8)]
-    pub enum SimpleType {
-        F32 = 0,
-        F64,
-        Bool,
-        Void,
-        USize,
-        ISize,
-        ComptimeInt,
-    }
-
-    impl From<u8> for SimpleType {
-        fn from(value: u8) -> Self {
-            match value {
-                0 => Self::F32,
-                1 => Self::F64,
-                2 => Self::Bool,
-                3 => Self::Void,
-                4 => Self::USize,
-                5 => Self::ISize,
-                6 => Self::ComptimeInt,
-                _ => panic!("{value} is not a simple type"),
-            }
-        }
-    }
-
-    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-    pub enum Tag {
-        String,
-        SIntSmall,
-        UIntSmall,
-        TrueValue,
-        FalseValue,
-        UInt64,
-        SInt64,
-        F32,
-        F64,
-        PositiveInt,
-        NegativeInt,
-        UIntType,
-        SIntType,
-        SimpleType,
-        PointerType,
-        ArrayType,
-        FunctionType,
-        StructType,
-    }
-
-    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-    struct Item {
-        tag: Tag,
-        index: u32,
-    }
-
-    #[derive(Debug, Clone, PartialEq)]
-    #[non_exhaustive]
-    pub enum Key<'a> {
-        String {
-            str: &'a str,
-        },
-        SIntSmall {
-            bits: i32,
-        },
-        UIntSmall {
-            bits: u32,
-        },
-        SInt64 {
-            bits: i64,
-        },
-        UInt64 {
-            bits: u64,
-        },
-        F32 {
-            bits: f32,
-        },
-        F64 {
-            bits: f64,
-        },
-        PositiveInt {
-            bigint: BigInt,
-        },
-        NegativeInt {
-            bigint: BigInt,
-        },
-        UIntType {
-            bits: u16,
-        },
-        SIntType {
-            bits: u16,
-        },
-        SimpleType {
-            ty: SimpleType,
-        },
-        PointerType {
-            pointee: Index,
-            flags: PointerFlags,
-        },
-        ArrayType {
-            pointee: Index,
-            flags: PointerFlags,
-            length: u32,
-        },
-        FunctionType {
-            return_type: Index,
-            parameters: Vec<Index>,
-        },
-        StructType {
-            decl: super::Index,
-            name: Index,
-            packed: bool,
-            c_like: bool,
-            /// vec of (Name, Type)
-            fields: Vec<(Index, Index)>,
-        },
-        TrueValue,
-        FalseValue,
-    }
-
-    impl Hash for Key<'_> {
-        fn hash<H: Hasher>(&self, state: &mut H) {
-            core::mem::discriminant(self).hash(state);
-            match self {
-                Key::String { str } => str.hash(state),
-                Key::SIntSmall { bits } => bits.hash(state),
-                Key::UIntSmall { bits } => bits.hash(state),
-                Key::SInt64 { bits } => bits.hash(state),
-                Key::UInt64 { bits } => bits.hash(state),
-                Key::F32 { bits } => ordered_float::OrderedFloat(*bits).hash(state),
-                Key::F64 { bits } => ordered_float::OrderedFloat(*bits).hash(state),
-                Key::PositiveInt { bigint } => bigint.hash(state),
-                Key::NegativeInt { bigint } => bigint.hash(state),
-                Key::UIntType { bits } => bits.hash(state),
-                Key::SIntType { bits } => bits.hash(state),
-                Key::SimpleType { ty } => ty.hash(state),
-                Key::PointerType { pointee, flags } => (pointee, flags).hash(state),
-                Key::ArrayType {
-                    pointee,
-                    flags,
-                    length,
-                } => (*pointee, *flags, *length).hash(state),
-                Key::StructType { name, decl, .. } => (*name, *decl).hash(state),
-                Key::FunctionType {
-                    return_type,
-                    parameters,
-                } => (return_type, parameters).hash(state),
-                Key::TrueValue | Key::FalseValue => {}
-            }
-        }
-    }
-
-    // #[repr(packed)]
-    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
-    pub struct PointerFlags {
-        pub volatile: bool,
-        pub is_const: bool,
-        pub noalias: bool,
-    }
-
-    impl PointerFlags {
-        pub fn new(is_const: bool, volatile: bool, noalias: bool) -> Self {
-            Self {
-                is_const,
-                volatile,
-                noalias,
-            }
-        }
-
-        pub fn pack(self) -> u8 {
-            (self.volatile as u8) << 0 | (self.is_const as u8) << 1 | (self.noalias as u8) << 2
-        }
-        pub fn unpack(packed: u8) -> Self {
-            Self {
-                volatile: packed & (1 << 0) != 0,
-                is_const: packed & (1 << 1) != 0,
-                noalias: packed & (1 << 2) != 0,
-            }
-        }
-    }
-
-    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
-    pub struct StructFlags {
-        pub packed: bool,
-        pub c_like: bool,
-        pub num_fields: u32,
-    }
-
-    impl StructFlags {
-        const MASK: u32 = (1u32 << 30) - 1;
-        pub fn new(packed: bool, c_like: bool, num_fields: u32) -> Self {
-            assert!(num_fields < (1 << 30));
-            Self {
-                packed,
-                c_like,
-                num_fields,
-            }
-        }
-        pub fn pack(self) -> u32 {
-            assert!(self.num_fields < (1 << 30));
-            (self.packed as u32) << 31 | (self.c_like as u32) << 30 | self.num_fields & Self::MASK
-        }
-        pub fn unpack(packed: u32) -> Self {
-            Self {
-                packed: packed & (1 << 31) != 0,
-                c_like: packed & (1 << 30) != 0,
-                num_fields: packed & Self::MASK,
-            }
-        }
-    }
-
-    #[derive(Debug, Clone, Copy)]
-    struct FunctionInfo {
-        void_return: bool,
-        num_params: u32,
-    }
-    impl FunctionInfo {
-        fn new(void_return: bool, num_params: u32) -> Self {
-            Self {
-                void_return,
-                num_params,
-            }
-        }
-
-        const MASK: u32 = 1u32 << (u32::BITS - 1);
-        fn pack(self) -> u32 {
-            (self.void_return as u32 * Self::MASK) | self.num_params & !Self::MASK
-        }
-        fn unpack(packed: u32) -> Self {
-            Self {
-                void_return: packed & Self::MASK != 0,
-                num_params: packed & !Self::MASK,
-            }
-        }
-        fn len(self) -> u32 {
-            self.void_return as u32 + self.num_params
-        }
-    }
-
-    impl Item {
-        fn idx(self) -> usize {
-            self.index as usize
-        }
-    }
-
-    #[repr(transparent)]
-    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct Index(pub u32);
-
-    impl Display for Index {
-        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            write!(f, "#{}", self.0)
-        }
-    }
-
-    impl Index {
-        pub fn into_u32(self) -> u32 {
-            unsafe { core::mem::transmute(self) }
-        }
-        pub fn as_u32(&self) -> &u32 {
-            unsafe { core::mem::transmute(self) }
-        }
-        fn index(&self) -> usize {
-            self.0 as usize
-        }
-
-        pub fn is_valid(&self) -> bool {
-            self.0 != u32::MAX
-        }
-
-        pub fn invalid() -> Self {
-            Self(u32::MAX)
-        }
-    }
-
-    pub struct InternPool {
-        tags: Vec<Tag>,
-        indices: Vec<u32>,
-        //
-        strings: Vec<u8>,
-        words: Vec<u32>,
-        hashed: BTreeMap<u64, Index>,
-    }
-
-    impl std::fmt::Debug for InternPool {
-        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            f.debug_struct("InternPool")
-                .field_with("keys", |f| {
-                    let mut list = f.debug_list();
-
-                    let keys = (0..self.indices.len())
-                        .map(|i| Index(i as u32))
-                        .map(|idx| (idx, self.get_key(idx)));
-                    for (idx, key) in keys {
-                        list.entry_with(|f| write!(f, "{}: {key:?}", idx.0));
-                    }
-
-                    list.finish()
-                })
-                .field_with("hashed", |f| {
-                    let mut list = f.debug_list();
-                    for (hash, idx) in self.hashed.iter() {
-                        list.entry_with(|f| write!(f, "{hash}: {}", idx.0));
-                    }
-                    list.finish()
-                })
-                .finish_non_exhaustive()
-        }
-    }
-
-    const STATIC_KEYS: [Key; 21] = [
-        Key::SimpleType {
-            ty: SimpleType::Bool,
-        },
-        Key::SimpleType {
-            ty: SimpleType::F32,
-        },
-        Key::SimpleType {
-            ty: SimpleType::F64,
-        },
-        Key::SimpleType {
-            ty: SimpleType::USize,
-        },
-        Key::SimpleType {
-            ty: SimpleType::ISize,
-        },
-        Key::SimpleType {
-            ty: SimpleType::Void,
-        },
-        Key::SimpleType {
-            ty: SimpleType::ComptimeInt,
-        },
-        Key::SIntType { bits: 1 },
-        Key::UIntType { bits: 1 },
-        Key::SIntType { bits: 0 },
-        Key::UIntType { bits: 0 },
-        Key::SIntType { bits: 8 },
-        Key::UIntType { bits: 8 },
-        Key::SIntType { bits: 16 },
-        Key::UIntType { bits: 16 },
-        Key::SIntType { bits: 32 },
-        Key::UIntType { bits: 32 },
-        Key::SIntType { bits: 64 },
-        Key::UIntType { bits: 64 },
-        Key::TrueValue,
-        Key::FalseValue,
-    ];
-
-    impl InternPool {
-        pub fn get_void_type(&self) -> Index {
-            self.get_assume_present(&Key::SimpleType {
-                ty: SimpleType::Void,
-            })
-        }
-        pub fn get_bool_type(&self) -> Index {
-            self.get_assume_present(&Key::SimpleType {
-                ty: SimpleType::Bool,
-            })
-        }
-        pub fn get_true_value(&self) -> Index {
-            self.get_assume_present(&Key::TrueValue)
-        }
-        pub fn get_false_value(&self) -> Index {
-            self.get_assume_present(&Key::FalseValue)
-        }
-        pub fn get_f32_type(&self) -> Index {
-            self.get_assume_present(&Key::SimpleType {
-                ty: SimpleType::F32,
-            })
-        }
-        pub fn get_f64_type(&self) -> Index {
-            self.get_assume_present(&Key::SimpleType {
-                ty: SimpleType::F64,
-            })
-        }
-        pub fn get_comptime_int_type(&self) -> Index {
-            self.get_assume_present(&Key::SimpleType {
-                ty: SimpleType::ComptimeInt,
-            })
-        }
-        pub fn get_usize_type(&self) -> Index {
-            self.get_assume_present(&Key::SimpleType {
-                ty: SimpleType::USize,
-            })
-        }
-        pub fn get_isize_type(&self) -> Index {
-            self.get_assume_present(&Key::SimpleType {
-                ty: SimpleType::ISize,
-            })
-        }
-        pub fn get_u0_type(&self) -> Index {
-            self.get_assume_present(&Key::UIntType { bits: 0 })
-        }
-        pub fn get_i0_type(&self) -> Index {
-            self.get_assume_present(&Key::SIntType { bits: 0 })
-        }
-        pub fn get_u1_type(&self) -> Index {
-            self.get_assume_present(&Key::UIntType { bits: 1 })
-        }
-        pub fn get_i1_type(&self) -> Index {
-            self.get_assume_present(&Key::SIntType { bits: 1 })
-        }
-        pub fn get_u8_type(&self) -> Index {
-            self.get_assume_present(&Key::UIntType { bits: 8 })
-        }
-        pub fn get_i8_type(&self) -> Index {
-            self.get_assume_present(&Key::SIntType { bits: 8 })
-        }
-        pub fn get_u16_type(&self) -> Index {
-            self.get_assume_present(&Key::UIntType { bits: 16 })
-        }
-        pub fn get_i16_type(&self) -> Index {
-            self.get_assume_present(&Key::SIntType { bits: 16 })
-        }
-        pub fn get_u32_type(&self) -> Index {
-            self.get_assume_present(&Key::UIntType { bits: 32 })
-        }
-        pub fn get_i32_type(&self) -> Index {
-            self.get_assume_present(&Key::SIntType { bits: 32 })
-        }
-        pub fn get_u64_type(&self) -> Index {
-            self.get_assume_present(&Key::UIntType { bits: 64 })
-        }
-        pub fn get_i64_type(&self) -> Index {
-            self.get_assume_present(&Key::SIntType { bits: 64 })
-        }
-    }
-
-    #[derive(Debug, Clone, Copy)]
-    pub struct TypeInfo {
-        pub bitsize: u32,
-        pub bitalign: u32,
-    }
-
-    impl InternPool {
-        pub fn size_of_type(&self, index: Index, ptr_size: TypeInfo) -> TypeInfo {
-            match self.get_key(index) {
-                Key::UIntType { bits } => {
-                    let bits = bits as u32;
-                    TypeInfo {
-                        bitsize: bits,
-                        bitalign: bits.next_multiple_of(8).next_power_of_two(),
-                    }
-                }
-                Key::SIntType { bits } => {
-                    let bits = bits as u32;
-                    TypeInfo {
-                        bitsize: bits,
-                        bitalign: bits.next_multiple_of(8).next_power_of_two(),
-                    }
-                }
-                Key::SimpleType { ty } => match ty {
-                    SimpleType::F32 => TypeInfo {
-                        bitsize: 32,
-                        bitalign: 32,
-                    },
-                    SimpleType::F64 => TypeInfo {
-                        bitsize: 64,
-                        bitalign: 64,
-                    },
-                    SimpleType::Bool => TypeInfo {
-                        bitsize: 1,
-                        bitalign: 1,
-                    },
-                    SimpleType::Void => TypeInfo {
-                        bitsize: 0,
-                        bitalign: 0,
-                    },
-                    SimpleType::USize => ptr_size,
-                    SimpleType::ISize => ptr_size,
-                    SimpleType::ComptimeInt => panic!("comptime int is unsized"),
-                },
-                Key::PointerType { .. } => ptr_size,
-                Key::ArrayType {
-                    pointee, length, ..
-                } => {
-                    let element_size = self.size_of_type(pointee, ptr_size);
-                    let bitsize = element_size.bitalign * length;
-                    TypeInfo {
-                        bitsize,
-                        ..element_size
-                    }
-                }
-                Key::FunctionType { .. } => ptr_size,
-                Key::StructType { packed, fields, .. } => {
-                    // TODO: c-like layout
-                    let (size, align) = fields.iter().fold((0, 0), |(size, align), (_name, ty)| {
-                        let field_size = self.size_of_type(*ty, ptr_size);
-                        let size = size + field_size.bitsize;
-
-                        let size = if packed {
-                            size.next_multiple_of(field_size.bitalign)
-                        } else {
-                            size
-                        };
-                        let align = align.max(field_size.bitalign);
-                        (size, align)
-                    });
-
-                    TypeInfo {
-                        bitsize: size,
-                        bitalign: align,
-                    }
-                }
-                _ => {
-                    panic!("index was not a type")
-                }
-            }
-        }
-
-        pub fn from_ast1_type(&self, pointer_bits: u16, ty: &crate::ast::Type) -> Index {
-            match ty {
-                crate::ast::Type::Bool => self.get_bool_type(),
-                crate::ast::Type::ComptimeNumber => self.get_comptime_int_type(),
-                crate::ast::Type::Integer(i) => self.get_assume_present(&{
-                    if i.signed {
-                        Key::SIntType { bits: i.bits }
-                    } else {
-                        Key::UIntType { bits: i.bits }
-                    }
-                }),
-                crate::ast::Type::Floating(crate::ast::FloatingType::Binary32) => {
-                    self.get_f32_type()
-                }
-                crate::ast::Type::Floating(crate::ast::FloatingType::Binary64) => {
-                    self.get_f64_type()
-                }
-                crate::ast::Type::Pointer { constness, pointee } => {
-                    self.get_assume_present(&Key::PointerType {
-                        pointee: self.from_ast1_type(pointer_bits, &pointee),
-                        flags: PointerFlags::new(*constness, false, false),
-                    })
-                }
-                crate::ast::Type::Fn { .. } => {
-                    unimplemented!()
-                }
-                _ => {
-                    todo!()
-                }
-            }
-        }
-
-        pub fn as_ast1_type(&self, pointer_bits: u16, index: Index) -> crate::ast::Type {
-            use crate::ast::Type;
-            match self.get_key(index) {
-                Key::UIntType { bits } => Type::Integer(IntegralType::new(false, bits)),
-                Key::SIntType { bits } => Type::Integer(IntegralType::new(true, bits)),
-                Key::SimpleType { ty } => match ty {
-                    SimpleType::F32 => Type::Floating(crate::ast::FloatingType::Binary32),
-                    SimpleType::F64 => Type::Floating(crate::ast::FloatingType::Binary64),
-                    SimpleType::Bool => Type::Bool,
-                    SimpleType::Void => Type::Void,
-                    SimpleType::USize => Type::Integer(IntegralType::new(false, pointer_bits)),
-                    SimpleType::ISize => Type::Integer(IntegralType::new(true, pointer_bits)),
-                    SimpleType::ComptimeInt => Type::comptime_number(),
-                },
-                Key::PointerType { pointee, flags } => Type::Pointer {
-                    constness: flags.is_const,
-                    pointee: Box::new(self.as_ast1_type(pointer_bits, pointee)),
-                },
-                Key::FunctionType {
-                    return_type,
-                    parameters,
-                } => Type::Fn {
-                    parameter_types: parameters
-                        .into_iter()
-                        .map(|i| self.as_ast1_type(pointer_bits, i))
-                        .collect(),
-                    return_type: Box::new(self.as_ast1_type(pointer_bits, return_type)),
-                },
-                _ => unimplemented!(),
-            }
-        }
-    }
-
-    pub const AMD64_POINTER_BITS: u16 = 64;
-
-    impl InternPool {
-        pub fn create() -> Self {
-            let mut this = Self {
-                tags: Vec::new(),
-                indices: Vec::new(),
-                strings: Vec::new(),
-                words: Vec::new(),
-                hashed: BTreeMap::new(),
-            };
-
-            this.extend_keys(STATIC_KEYS);
-
-            this
-        }
-
-        fn extend_keys<'a, K: IntoIterator<Item = Key<'a>>>(&mut self, keys: K) {
-            for k in keys.into_iter() {
-                let mut hasher = std::hash::DefaultHasher::new();
-                k.hash(&mut hasher);
-                let digest = hasher.finish();
-                let i = self.insert(k);
-                self.hashed.insert(digest, i);
-            }
-        }
-
-        fn len(&self) -> u32 {
-            u32::try_from(self.tags.len())
-                .expect(&format!("more than {} items in internpool!", u32::MAX))
-        }
-
-        pub fn get_or_insert(&mut self, key: Key) -> Index {
-            let mut hasher = std::hash::DefaultHasher::new();
-            key.hash(&mut hasher);
-            let digest = hasher.finish();
-            if let Some(&idx) = self.hashed.get(&digest) {
-                idx
-            } else {
-                let i = self.insert(key);
-                self.hashed.insert(digest, i);
-                i
-            }
-        }
-
-        fn insert(&mut self, key: Key) -> Index {
-            match key {
-                Key::String { str } => {
-                    let len = str.len() as u32;
-                    let start = self.extend_strings(str);
-
-                    let words_idx = self.extend_words([start, len]);
-                    self.create_item(Tag::String, words_idx)
-                }
-                Key::SIntSmall { bits } => self.create_item(Tag::SIntSmall, bits as u32),
-                Key::UIntSmall { bits } => self.create_item(Tag::UIntSmall, bits as u32),
-                Key::F32 { bits } => self.create_item(Tag::F32, bits as u32),
-                Key::F64 { bits } => {
-                    let (lo, hi) = into_lo_hi_dwords(bits as u64);
-                    let words_idx = self.extend_words([lo, hi]);
-                    self.create_item(Tag::F64, words_idx)
-                }
-                Key::SInt64 { bits } => {
-                    let (lo, hi) = into_lo_hi_dwords(bits as u64);
-                    let i = self.extend_words([lo, hi]);
-                    self.create_item(Tag::SInt64, i)
-                }
-                Key::UInt64 { bits } => {
-                    let (lo, hi) = into_lo_hi_dwords(bits as u64);
-                    let i = self.extend_words([lo, hi]);
-                    self.create_item(Tag::UInt64, i)
-                }
-                Key::PositiveInt { bigint } => {
-                    let (_, words) = bigint.to_u32_digits();
-                    let i = self.push_word(words.len() as u32);
-                    _ = self.extend_words(words);
-                    self.create_item(Tag::PositiveInt, i)
-                }
-                Key::NegativeInt { bigint } => {
-                    let (_, words) = bigint.to_u32_digits();
-                    let i = self.push_word(words.len() as u32);
-                    _ = self.extend_words(words);
-                    self.create_item(Tag::NegativeInt, i)
-                }
-
-                Key::UIntType { bits } => self.create_item(Tag::UIntType, bits as u32),
-                Key::SIntType { bits } => self.create_item(Tag::SIntType, bits as u32),
-                Key::SimpleType { ty } => self.create_item(Tag::SimpleType, ty as u8 as u32),
-                Key::PointerType { pointee, flags } => {
-                    let flags = flags.pack();
-                    let i = self.extend_words([pointee.0, flags as u32]);
-                    self.create_item(Tag::PointerType, i)
-                }
-                Key::ArrayType {
-                    pointee,
-                    flags,
-                    length,
-                } => {
-                    let flags = flags.pack();
-                    let i = self.extend_words([pointee.0, flags as u32, length]);
-                    self.create_item(Tag::ArrayType, i)
-                }
-                Key::StructType {
-                    name,
-                    decl,
-                    packed,
-                    c_like,
-                    fields,
-                } => {
-                    let flags = StructFlags::new(packed, c_like, fields.len() as u32).pack();
-                    let i = self.extend_words([name.into_u32(), decl.into_u32(), flags, u32::MAX]);
-                    if !fields.is_empty() {
-                        let fields_offset = self.extend_words(
-                            fields
-                                .into_iter()
-                                .map(|(n, t)| [n.into_u32(), t.into_u32()])
-                                .flatten(),
-                        );
-                        self.words[i as usize + 3] = fields_offset;
-                    }
-                    self.create_item(Tag::StructType, i)
-                }
-                Key::FunctionType {
-                    return_type,
-                    parameters,
-                } => {
-                    let info = FunctionInfo::new(
-                        return_type == self.get_simple_type(SimpleType::Void),
-                        parameters.len() as u32,
-                    );
-
-                    let start = self.push_word(info.pack());
-                    self.extend_words([return_type.into_u32()]);
-                    _ = self.extend_words(parameters.into_iter().map(|i| i.0));
-
-                    self.create_item(Tag::FunctionType, start)
-                }
-                Key::TrueValue => self.create_item(Tag::TrueValue, 0),
-                Key::FalseValue => self.create_item(Tag::FalseValue, 0),
-            }
-        }
-
-        fn extend_strings<B: AsRef<[u8]>>(&mut self, b: B) -> u32 {
-            let idx = self.strings.len() as u32;
-            self.strings.extend(b.as_ref());
-            idx
-        }
-        fn extend_words<I: IntoIterator<Item = u32>>(&mut self, i: I) -> u32 {
-            let idx = self.words.len() as u32;
-            self.words.extend(i);
-            idx
-        }
-        fn push_word(&mut self, word: u32) -> u32 {
-            let idx = self.words.len() as u32;
-            self.words.push(word);
-            idx
-        }
-
-        fn create_item(&mut self, tag: Tag, index: u32) -> Index {
-            let len = self.len();
-            self.tags.push(tag);
-            self.indices.push(index);
-            Index(len)
-        }
-
-        pub fn get_key(&self, index: Index) -> Key {
-            let item = self.get_item(index).unwrap();
-            match item.tag {
-                Tag::String => {
-                    let start = self.words[item.idx()];
-                    let len = self.words[item.idx() + 1];
-                    let str = unsafe {
-                        core::str::from_utf8_unchecked(
-                            &self.strings[start as usize..][..len as usize],
-                        )
-                    };
-                    Key::String { str }
-                }
-                Tag::UIntSmall => Key::UIntSmall {
-                    bits: item.index as u32,
-                },
-                Tag::SIntSmall => Key::SIntSmall {
-                    bits: item.index as i32,
-                },
-                Tag::F32 => Key::F32 {
-                    bits: f32::from_le_bytes(item.index.to_le_bytes()),
-                },
-                Tag::F64 => {
-                    let idx = item.idx();
-                    let bits = from_lo_hi_dwords(self.words[idx], self.words[idx + 1]);
-                    Key::F64 {
-                        bits: f64::from_le_bytes(bits.to_le_bytes()),
-                    }
-                }
-                Tag::SInt64 => {
-                    let bits = from_lo_hi_dwords(self.words[item.idx()], self.words[item.idx() + 1])
-                        as i64;
-                    Key::SInt64 { bits }
-                }
-                Tag::UInt64 => {
-                    let bits =
-                        from_lo_hi_dwords(self.words[item.idx()], self.words[item.idx() + 1]);
-                    Key::UInt64 { bits }
-                }
-                Tag::NegativeInt => {
-                    let len = self.words[item.idx()];
-                    let start = item.idx() + 1;
-                    let end = start + len as usize;
-                    let data = BigUint::from_slice(&self.words[start..end]);
-                    let bigint = BigInt::from_biguint(Sign::Minus, data);
-                    Key::NegativeInt { bigint }
-                }
-                Tag::PositiveInt => {
-                    let len = self.words[item.idx()];
-                    let start = item.idx() + 1;
-                    let end = start + len as usize;
-                    let data = BigUint::from_slice(&self.words[start..end]);
-                    let bigint = BigInt::from_biguint(Sign::Plus, data);
-                    Key::PositiveInt { bigint }
-                }
-                Tag::SIntType => Key::SIntType {
-                    bits: item.index as u16,
-                },
-                Tag::UIntType => Key::UIntType {
-                    bits: item.index as u16,
-                },
-                Tag::SimpleType => {
-                    let ty = item.idx() as u8;
-
-                    Key::SimpleType {
-                        ty: unsafe { core::mem::transmute::<u8, SimpleType>(ty) },
-                    }
-                }
-                Tag::PointerType => {
-                    let pointee = Index(self.words[item.idx()]);
-                    let flags = PointerFlags::unpack(self.words[item.idx() + 1] as u8);
-
-                    Key::PointerType { pointee, flags }
-                }
-                Tag::ArrayType => {
-                    let pointee = Index(self.words[item.idx()]);
-                    let flags = PointerFlags::unpack(self.words[item.idx() + 1] as u8);
-                    let length = self.words[item.idx() + 2];
-
-                    Key::ArrayType {
-                        pointee,
-                        flags,
-                        length,
-                    }
-                }
-                Tag::StructType => {
-                    let name = Index(self.words[item.idx()]);
-                    let decl = super::Index::new(self.words[item.idx() + 1]);
-                    let flags = StructFlags::unpack(self.words[item.idx() + 2]);
-                    let fields = if flags.num_fields != 0 {
-                        let fields_offset = self.words[item.idx() + 3] as usize;
-                        let fields_end = fields_offset + flags.num_fields as usize * 2;
-
-                        self.words[fields_offset..fields_end]
-                            .iter()
-                            .cloned()
-                            .array_chunks::<2>()
-                            .map(|[n, t]| (Index(n), Index(t)))
-                            .collect::<Vec<_>>()
-                    } else {
-                        vec![]
-                    };
-
-                    Key::StructType {
-                        name,
-                        decl,
-                        packed: flags.packed,
-                        c_like: flags.c_like,
-                        fields,
-                    }
-                }
-                Tag::FunctionType => {
-                    let info = FunctionInfo::unpack(self.words[item.idx()]);
-                    let len = info.len();
-                    let (return_type, parameters) = if info.void_return {
-                        let start = item.idx() + 1;
-                        let end = start + len as usize;
-                        let params = self.words[start..end]
-                            .iter()
-                            .map(|&i| Index(i))
-                            .collect::<Vec<_>>();
-                        (
-                            self.get_assume_present(&Key::SimpleType {
-                                ty: SimpleType::Void,
-                            }),
-                            params,
-                        )
-                    } else {
-                        let return_type = Index(self.words[item.idx() + 1]);
-                        let start = item.idx() + 2;
-                        let end = start + len as usize;
-                        let params = self.words[start..end]
-                            .iter()
-                            .map(|&i| Index(i))
-                            .collect::<Vec<_>>();
-                        (return_type, params)
-                    };
-
-                    Key::FunctionType {
-                        return_type,
-                        parameters,
-                    }
-                }
-                Tag::TrueValue => Key::TrueValue,
-                Tag::FalseValue => Key::FalseValue,
-            }
-        }
-
-        pub fn try_get_index(&self, key: &Key) -> Option<Index> {
-            let mut hasher = std::hash::DefaultHasher::new();
-            key.hash(&mut hasher);
-            let digest = hasher.finish();
-            self.hashed.get(&digest).cloned()
-        }
-
-        pub fn get_assume_present(&self, key: &Key) -> Index {
-            self.try_get_index(&key)
-                .expect(&format!("key {key:?} not present in pool."))
-        }
-
-        pub fn get_int_type(&mut self, signed: bool, bits: u16) -> Index {
-            let key = match signed {
-                true => Key::SIntType { bits },
-                false => Key::UIntType { bits },
-            };
-
-            self.get_or_insert(key)
-        }
-
-        pub fn get_string_index(&mut self, str: &str) -> Index {
-            self.get_or_insert(Key::String { str })
-        }
-        pub fn try_get_string_index(&self, str: &str) -> Option<Index> {
-            self.try_get_index(&Key::String { str })
-        }
-
-        pub fn get_simple_type(&mut self, ty: SimpleType) -> Index {
-            self.get_or_insert(Key::SimpleType { ty })
-        }
-        pub fn try_get_simple_type(&self, ty: SimpleType) -> Option<Index> {
-            self.try_get_index(&Key::SimpleType { ty })
-        }
-
-        pub fn get_function_type<P: IntoIterator<Item = Index>>(
-            &mut self,
-            return_type: Index,
-            parameters: P,
-        ) -> Index {
-            self.get_or_insert(Key::FunctionType {
-                return_type,
-                parameters: parameters.into_iter().collect(),
-            })
-        }
-
-        pub fn try_get_function_type<P: IntoIterator<Item = Index>>(
-            &self,
-            return_type: Index,
-            parameters: P,
-        ) -> Option<Index> {
-            self.try_get_index(&Key::FunctionType {
-                return_type,
-                parameters: parameters.into_iter().collect(),
-            })
-        }
-
-        pub fn get_pointer_type(&mut self, pointee: Index, flags: Option<PointerFlags>) -> Index {
-            let key = Key::PointerType {
-                pointee,
-                flags: flags.unwrap_or_default(),
-            };
-            self.get_or_insert(key)
-        }
-        pub fn try_get_pointer_type(
-            &self,
-            pointee: Index,
-            flags: Option<PointerFlags>,
-        ) -> Option<Index> {
-            self.try_get_index(
-                &(Key::PointerType {
-                    pointee,
-                    flags: flags.unwrap_or_default(),
-                }),
-            )
-        }
-
-        pub fn insert_or_replace_struct_type<I: IntoIterator<Item = (Index, Index)>>(
-            &mut self,
-            name: Index,
-            decl: super::Index,
-            packed: bool,
-            c_like: bool,
-            fields: I,
-        ) -> Index {
-            let key = Key::StructType {
-                name,
-                decl,
-                packed,
-                c_like,
-                fields: vec![],
-            };
-            if let Some(i) = self.try_get_index(&key).and_then(|i| self.get_item(i)) {
-                let fields_offset = self.extend_words(
-                    fields
-                        .into_iter()
-                        .map(|(n, t)| [n.into_u32(), t.into_u32()])
-                        .flatten(),
-                );
-                self.words[i.idx() + 3] = fields_offset;
-                let fields_end = self.words.len() as u32;
-                let num_fields = (fields_end - fields_offset) / 2;
-                let flags = StructFlags::new(packed, c_like, num_fields).pack();
-                self.words[i.idx() + 2] = flags;
-            }
-            self.get_or_insert(key)
-        }
-
-        pub fn get_struct_type(&mut self, name: Index, decl: super::Index) -> Index {
-            let key = Key::StructType {
-                name,
-                decl,
-                packed: false,
-                c_like: false,
-                fields: vec![],
-            };
-            self.get_or_insert(key)
-        }
-        pub fn try_get_struct_type(&self, name: Index, decl: super::Index) -> Option<Index> {
-            self.try_get_index(&Key::StructType {
-                name,
-                decl,
-                packed: false,
-                c_like: false,
-                fields: vec![],
-            })
-        }
-
-        pub fn get_array_type(
-            &mut self,
-            pointee: Index,
-            flags: Option<PointerFlags>,
-            length: u32,
-        ) -> Index {
-            let key = Key::ArrayType {
-                pointee,
-                flags: flags.unwrap_or_default(),
-                length,
-            };
-            self.get_or_insert(key)
-        }
-        pub fn try_get_array_type(
-            &self,
-            pointee: Index,
-            flags: Option<PointerFlags>,
-            length: u32,
-        ) -> Option<Index> {
-            self.try_get_index(&Key::ArrayType {
-                pointee,
-                flags: flags.unwrap_or_default(),
-                length,
-            })
-        }
-
-        pub fn get_str(&self, index: Index) -> &str {
-            let key = self.get_key(index);
-            assert!(matches!(key, Key::String { .. }));
-            variant!(key => Key::String { str });
-
-            str
-        }
-
-        fn check_bounds(&self, index: Index) -> Option<Index> {
-            (index.0 < self.len()).then_some(index)
-        }
-
-        fn get_item(&self, index: Index) -> Option<Item> {
-            self.check_bounds(index).map(|i| Item {
-                tag: self.tags[i.index()],
-                index: self.indices[i.index()],
-            })
-        }
-    }
-}
+pub mod intern;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 enum Tag {