SeaLang/src/ast2/mod.rs

4382 lines
150 KiB
Rust

#![allow(dead_code)]
use std::{
collections::BTreeMap,
fmt::{Debug, Display},
num::NonZero,
};
use intern::{InternPool, PointerFlags, StructFlags};
use num_bigint::BigInt;
use crate::{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::{
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")
}
}
}
}
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()],
})
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Tag {
/// pseudo tag, contains a range from a..b into extra of all files.
Root,
/// `data` is a range from a..b into extra of all global nodes.
File,
/// `data` is an intern to a name, and an index into extra of [index: return_type, index: ParameterList]
FunctionProto,
/// `data` is an index to a FunctionProto and an index to a Block
FunctionDecl,
/// `data` is a range from a..b into extra of indices to parameters
ParameterList,
/// `data` is an index to a type, and an intern to a name
Parameter,
/// `data` is range from a..b into `extra` of indices to statements
Block,
/// `data` is range from a..b into `extra` of indices to statements, where the last one is an expression
BlockTrailingExpr,
/// `data` is an index to a type, and an intern to a value
Constant,
/// `data` is an index to an expression
ExprStmt,
/// `data` is none
ReturnStmt,
/// `data` is an index to an expr
ReturnExprStmt,
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
VarDecl,
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
MutVarDecl,
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
VarDeclAssignment,
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
MutVarDeclAssignment,
/// `data` is an intern to a name, and an offset into `extra` of `[type: index, expr: index]`
GlobalDecl,
/// `data` is an intern to a name, and an offset into extra of `[flags, type0 ,..., typeN ,name0 ,..., nameN]`
StructDecl,
/// `data` is an index to a type, and an intern to a name
FieldDecl,
/// `data` is an index to a VarDecl, GlobalDecl or FunctionDecl
DeclRef,
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
DeclRefUnresolved,
/// `data` is an intern of a type
InternedType,
/// `data` is an index to a StructDecl
TypeDeclRef,
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
TypeDeclRefUnresolved,
/// `data` is an index to a Type and u32 PointerFlags
PointerType,
/// `data` is an index to a length expression, and an underlying pointer type
ArrayType,
/// `data` is an index to an expr and an index to an ArgumentList
CallExpr,
/// `data` is an index to an expr and an intern to a field name
FieldAccess,
/// `data` is a range from a..b into extra of indices to arguments
ArgumentList,
/// `data` is an index to an expression
Argument,
/// `data` is an index to an expression, and an intern to a name
NamedArgument,
/// `data` is an index to lhs, and an index to the type
ExplicitCast,
/// `data` is a single index to an expr
Deref,
AddressOf,
Not,
Negate,
/// data is two indices for `lhs` and `rhs`
Or,
And,
BitOr,
BitXOr,
BitAnd,
Eq,
NEq,
Lt,
Gt,
Le,
Ge,
Shl,
Shr,
Add,
Sub,
Mul,
Div,
Rem,
Assign,
SubscriptExpr,
IfExpr,
/// `data` is an index to an expression and an index into extra for [if, else]
IfElseExpr,
// TODO:
/// `data` is a ParseError
Error,
/// placeholder tag for reserved indices/nodes, `data` is none
Undefined,
}
#[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)]
enum ParseError {
#[error("Unexpected end of token iter.")]
UnexpectedEndOfTokens,
#[error("Expected Token {0}.")]
ExpectedToken(Token),
#[error("Expected Token {0}, but other token was found.")]
ExpectedTokenNotFound(Token),
#[error("Expected either a function declaration or a global variable.")]
UnexpectedTokenAtFileScope,
#[error("Expected Ident.")]
ExpectedIdent,
#[error("Integral types may not be wider than 65535 bits.")]
IntegralTypeTooWide,
#[error("Expected typename.")]
ExpectedTypeName,
#[error("Dummy Message.")]
ExpectedFunctionPrototype,
#[error("Dummy Message.")]
ExpectedPrimaryExpression,
#[error("Dummy Message.")]
ExpectedConstantLiteral,
#[error("Dummy Message.")]
ExpectedExpression,
#[error("Dummy Message.")]
ExpectedPostfixExpression,
#[error("Dummy Message.")]
ExpectedPrefixExpression,
#[error("Dummy Message.")]
ExpectedArgumentList,
#[error("Dummy Message.")]
ExpectedStatement,
#[error("Dummy Message.")]
UnmatchedParens(u32),
#[error("Dummy Message.")]
ExpectedTypeDeclaration,
#[error("Dummy Message.")]
UnexpectedTypeAttributes,
#[error("Dummy Message.")]
UnmatchedSquareBracket(u32),
#[error("Dummy Message.")]
ExpectedEndOfBlock,
#[error("Dummy Message.")]
UnmatchedBrace(u32),
#[error("Dummy Message.")]
UnmatchedDelimiter(u32),
#[error("Error in child node {0:?}.")]
ErrorNode(Index),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Index(NonZero<u32>);
impl Display for Index {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "%{}", self.0.get())
}
}
impl Index {
pub fn new(i: u32) -> Index {
Self(NonZero::<u32>::new(i).unwrap())
}
pub fn as_u32(&self) -> &u32 {
unsafe { core::mem::transmute(self) }
}
pub fn into_u32(self) -> u32 {
unsafe { core::mem::transmute(self) }
}
fn index(self) -> usize {
self.0.get() as usize
}
}
#[repr(packed)]
#[derive(Clone, Copy)]
struct Node {
/// defines the type of the node in the tree
tag: Tag,
data: Data,
}
#[derive(Clone, Copy)]
union Data {
none: (),
error: ParseError,
index: Index,
two_indices: (Index, Index),
range: (Index, Index),
extra_range: (u32, u32),
intern: intern::Index,
index_intern: (Index, intern::Index),
two_interns: (intern::Index, intern::Index),
intern_and_extra_offset: (intern::Index, u32),
index_and_extra_offset: (Index, u32),
}
#[derive(Debug)]
#[allow(dead_code)]
enum ExpandedData {
None,
Error(ParseError),
Index(Index),
TwoIndices(Index, Index),
Range(Index, Index),
ExtraRange(usize, usize),
Intern(intern::Index),
IndexIntern(Index, intern::Index),
TwoInterns(intern::Index, intern::Index),
InternAndExtraOffset(intern::Index, usize),
IndexAndExtraOffset(Index, usize),
}
impl ExpandedData {
fn from_none(data: Data) -> Self {
Self::None
}
fn from_error(data: Data) -> Self {
Self::Error(data.as_error())
}
fn from_index(data: Data) -> Self {
Self::Index(data.as_index())
}
fn from_two_indices(data: Data) -> Self {
let data = data.as_two_indices();
Self::TwoIndices(data.0, data.1)
}
fn from_range(data: Data) -> Self {
let data = data.as_index_range();
Self::Range(data.0, data.1)
}
fn from_extra_range(data: Data) -> Self {
let data = data.as_extra_range();
Self::ExtraRange(data.0, data.1)
}
fn from_intern(data: Data) -> Self {
let data = data.as_intern();
Self::Intern(data)
}
fn from_index_intern(data: Data) -> Self {
let data = data.as_index_intern();
Self::IndexIntern(data.0, data.1)
}
fn from_two_interns(data: Data) -> Self {
let data = data.as_two_interns();
Self::TwoInterns(data.0, data.1)
}
fn from_intern_and_extra_offset(data: Data) -> Self {
let data = data.as_intern_and_extra_offset();
Self::InternAndExtraOffset(data.0, data.1)
}
fn from_index_and_extra_offset(data: Data) -> Self {
let data = data.as_index_and_extra_offset();
Self::IndexAndExtraOffset(data.0, data.1)
}
}
impl From<(Tag, Data)> for ExpandedData {
fn from((tag, data): (Tag, Data)) -> Self {
match tag {
Tag::FunctionProto => Self::from_index_and_extra_offset(data),
Tag::ParameterList => Self::from_extra_range(data),
Tag::Root => Self::from_extra_range(data),
Tag::File => Self::from_extra_range(data),
Tag::ArgumentList
| Tag::VarDecl
| Tag::MutVarDecl
| Tag::VarDeclAssignment
| Tag::MutVarDeclAssignment
| Tag::BlockTrailingExpr
| Tag::Block => Self::from_extra_range(data),
Tag::FieldDecl | Tag::Constant | Tag::Parameter => Self::from_index_intern(data),
Tag::Or
| Tag::And
| Tag::BitOr
| Tag::BitXOr
| Tag::BitAnd
| Tag::Eq
| Tag::NEq
| Tag::Lt
| Tag::Gt
| Tag::Le
| Tag::Ge
| Tag::Shl
| Tag::Shr
| Tag::Add
| Tag::Sub
| Tag::Mul
| Tag::Div
| Tag::Rem
| Tag::Assign
| Tag::IfExpr
| Tag::SubscriptExpr
| Tag::CallExpr
| Tag::ArrayType
| Tag::FunctionDecl => Self::from_two_indices(data),
Tag::ReturnExprStmt
| Tag::DeclRef
| Tag::TypeDeclRef
| Tag::Argument
| Tag::Deref
| Tag::AddressOf
| Tag::Not
| Tag::Negate
| Tag::ExprStmt => Self::from_index(data),
Tag::FieldAccess
| Tag::DeclRefUnresolved
| Tag::TypeDeclRefUnresolved
| Tag::NamedArgument
| Tag::ExplicitCast => Self::from_index_intern(data),
Tag::GlobalDecl => Self::from_intern_and_extra_offset(data),
Tag::InternedType | Tag::StructDecl => Self::from_intern(data),
Tag::PointerType | Tag::IfElseExpr => Self::from_index_and_extra_offset(data),
Tag::Error => Self::from_error(data),
Tag::ReturnStmt | Tag::Undefined => Self::from_none(data),
}
}
}
impl Data {
fn as_error(self) -> ParseError {
unsafe { self.error }
}
fn as_index(self) -> Index {
unsafe { self.index }
}
fn as_two_indices(self) -> (Index, Index) {
unsafe { self.two_indices }
}
fn as_index_range(self) -> (Index, Index) {
unsafe { self.range }
}
fn as_extra_range(self) -> (usize, usize) {
let (a, b) = unsafe { self.extra_range };
(a as usize, b as usize)
}
fn as_intern(self) -> intern::Index {
unsafe { self.intern }
}
fn as_two_interns(self) -> (intern::Index, intern::Index) {
unsafe { self.two_interns }
}
fn as_index_intern(self) -> (Index, intern::Index) {
unsafe { self.index_intern }
}
fn as_index_and_extra_offset(self) -> (Index, usize) {
let (i, e) = unsafe { self.index_and_extra_offset };
(i, e as usize)
}
fn as_intern_and_extra_offset(self) -> (intern::Index, usize) {
let (i, e) = unsafe { self.intern_and_extra_offset };
(i, e as usize)
}
}
impl Data {
fn none() -> Self {
Self { none: () }
}
fn error(error: ParseError) -> Self {
Self { error }
}
fn index(index: Index) -> Self {
Self { index }
}
fn two_indices(a: Index, b: Index) -> Self {
Self {
two_indices: (a, b),
}
}
fn two_interns(a: intern::Index, b: intern::Index) -> Self {
Self {
two_interns: (a, b),
}
}
fn range_of_indices(a: Index, b: Index) -> Self {
Self { range: (a, b) }
}
fn extra_range(a: u32, b: u32) -> Self {
Self {
extra_range: (a, b),
}
}
fn intern(intern: intern::Index) -> Self {
Self { intern }
}
fn index_and_intern(index: Index, intern: intern::Index) -> Self {
Self {
index_intern: (index, intern),
}
}
fn intern_and_extra_offset(intern: intern::Index, offset: u32) -> Self {
Self {
intern_and_extra_offset: (intern, offset),
}
}
fn index_and_extra_offset(index: Index, offset: u32) -> Self {
Self {
index_and_extra_offset: (index, offset),
}
}
}
pub struct Ast {
tags: Vec<Tag>,
datas: Vec<Data>,
extra: Vec<u32>,
source_locs: Vec<SourceLocation>,
}
impl Debug for Ast {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Ast")
.field_with("nodes", |f| {
let mut list = f.debug_list();
struct LocDisplay(SourceLocation);
impl Debug for LocDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({})", self.0)
}
}
let entries = self
.tags
.iter()
.cloned()
.zip(self.datas.iter().cloned())
.zip(self.source_locs.iter().cloned())
.enumerate()
.map(|(i, ((tag, data), loc))| {
(i, tag, ExpandedData::from((tag, data)), LocDisplay(loc))
});
list.entries(entries).finish()
})
.field("extra", &self.extra)
.finish()
}
}
impl Ast {
fn new() -> Ast {
Self {
tags: vec![Tag::Root],
datas: vec![Data::extra_range(0, 0)],
extra: vec![],
source_locs: vec![SourceLocation::new(0, 0)],
}
}
fn reserve_node(&mut self) -> Index {
let i = unsafe { Index(NonZero::new_unchecked(self.tags.len() as u32)) };
self.tags.push(Tag::Undefined);
self.datas.push(Data::none());
self.source_locs.push(SourceLocation::invalid());
i
}
fn get_loc(&self, index: Index) -> SourceLocation {
self.source_locs[index.index()]
}
fn push_error(&mut self, error: ParseError, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::Error, Data::error(error), loc);
i
}
fn set_file<I: IntoIterator<Item = Index>>(&mut self, i: Index, decls: I, loc: SourceLocation) {
let (extra_start, extra_end) = self.extend_extra_by_indices(decls);
self.set_tag_data_source_loc(i, Tag::File, Data::extra_range(extra_start, extra_end), loc);
}
fn push_file<I: IntoIterator<Item = Index>>(&mut self, decls: I, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_file(i, decls, loc);
i
}
fn set_root<I: IntoIterator<Item = Index>>(&mut self, decls: I) {
let (extra_start, extra_end) = self.extend_extra_by_indices(decls);
self.tags[0] = Tag::Root;
self.datas[0] = Data::extra_range(extra_start, extra_end);
}
fn get_root_file_indices<'a>(&'a self) -> impl Iterator<Item = Index> + 'a {
let (a, b) = self.datas[0].as_extra_range();
self.extra[a..b].iter().cloned().map(|i| Index::new(i))
}
fn push_global_decl(
&mut self,
ident: intern::Index,
ty: Index,
expr: Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
let (extra_start, _) = self.extend_extra([ty.into_u32(), expr.into_u32()]);
self.set_tag_data_source_loc(
i,
Tag::GlobalDecl,
Data::intern_and_extra_offset(ident, extra_start),
loc,
);
i
}
fn set_fn_decl(&mut self, i: Index, proto: Index, body: Index, loc: SourceLocation) {
self.set_tag_data_source_loc(i, Tag::FunctionDecl, Data::two_indices(proto, body), loc);
}
fn push_fn_decl(&mut self, proto: Index, body: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_fn_decl(i, proto, body, loc);
i
}
fn push_ret(&mut self, expr: Option<Index>, loc: SourceLocation) -> Index {
let i = self.reserve_node();
match expr {
Some(expr) => {
self.set_tag_data_source_loc(i, Tag::ReturnExprStmt, Data::index(expr), loc)
}
None => self.set_tag_data_source_loc(i, Tag::ReturnStmt, Data::none(), loc),
}
i
}
fn push_var_decl(
&mut self,
is_let: bool,
name: intern::Index,
ty: Option<Index>,
assignment: Option<Index>,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
let start = self.extra.len() as u32;
self.extra.push(name.into_u32());
_ = self.extend_extra(assignment.map(|i| i.into_u32()));
_ = self.extend_extra(ty.map(|i| i.into_u32()));
let end = self.extra.len() as u32;
let tag = match (is_let, assignment.is_some()) {
(true, false) => Tag::VarDecl,
(true, true) => Tag::VarDeclAssignment,
(false, false) => Tag::MutVarDecl,
(false, true) => Tag::MutVarDeclAssignment,
};
self.set_tag_data_source_loc(i, tag, Data::extra_range(start, end), loc);
i
}
fn push_fn_proto(
&mut self,
ident: intern::Index,
return_type: Index,
parameter_list: Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
let (extra_start, _) =
self.extend_extra([return_type.into_u32(), parameter_list.into_u32()]);
self.set_tag_data_source_loc(
i,
Tag::FunctionProto,
Data::intern_and_extra_offset(ident, extra_start),
loc,
);
i
}
fn set_block<I: IntoIterator<Item = Index>>(
&mut self,
i: Index,
statements: I,
trailing: Option<Index>,
loc: SourceLocation,
) {
let (extra_start, extra_end) =
self.extend_extra_by_indices(statements.into_iter().chain(trailing.into_iter()));
if trailing.is_some() {
self.set_tag_data_source_loc(
i,
Tag::BlockTrailingExpr,
Data::extra_range(extra_start, extra_end),
loc,
);
} else {
self.set_tag_data_source_loc(
i,
Tag::Block,
Data::extra_range(extra_start, extra_end),
loc,
);
}
}
fn push_block<I: IntoIterator<Item = Index>>(
&mut self,
statements: I,
trailing: Option<Index>,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
self.set_block(i, statements, trailing, loc);
i
}
fn push_parameter_list<I: IntoIterator<Item = Index>>(
&mut self,
parameters: I,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
let (extra_start, extra_end) = self.extend_extra_by_indices(parameters);
self.set_tag_data_source_loc(
i,
Tag::ParameterList,
Data::extra_range(extra_start, extra_end),
loc,
);
i
}
fn push_argument(&mut self, expr: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::Argument, Data::index(expr), loc);
i
}
fn push_named_argument(
&mut self,
name: intern::Index,
expr: Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(
i,
Tag::NamedArgument,
Data::index_and_intern(expr, name),
loc,
);
i
}
fn push_parameter(&mut self, name: intern::Index, ty: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::Parameter, Data::index_and_intern(ty, name), loc);
i
}
fn push_argument_list<I: IntoIterator<Item = Index>>(
&mut self,
args: I,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
let (extra_start, extra_end) = self.extend_extra_by_indices(args);
self.set_tag_data_source_loc(
i,
Tag::ArgumentList,
Data::extra_range(extra_start, extra_end),
loc,
);
i
}
fn push_unary(&mut self, tag: Tag, lhs: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, tag, Data::index(lhs), loc);
i
}
fn push_binary(&mut self, tag: Tag, lhs: Index, rhs: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, tag, Data::two_indices(lhs, rhs), loc);
i
}
fn push_assign(&mut self, lhs: Index, rhs: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::Assign, Data::two_indices(lhs, rhs), loc);
i
}
fn push_cast(&mut self, lhs: Index, ty: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::ExplicitCast, Data::two_indices(lhs, ty), loc);
i
}
fn push_if(&mut self, cond: Index, body: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::IfExpr, Data::two_indices(cond, body), loc);
i
}
fn push_if_else(
&mut self,
cond: Index,
body: Index,
other: Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
let (extra_start, _) = self.extend_extra_by_indices([body, other]);
self.set_tag_data_source_loc(
i,
Tag::IfElseExpr,
Data::index_and_extra_offset(cond, extra_start),
loc,
);
i
}
fn push_call_expr(&mut self, lhs: Index, args: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::CallExpr, Data::two_indices(lhs, args), loc);
i
}
fn push_decl_ref_unresolved(
&mut self,
scope: Index,
ident: intern::Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(
i,
Tag::DeclRefUnresolved,
Data::index_and_intern(scope, ident),
loc,
);
i
}
fn resolve_decl_ref(&mut self, i: Index, decl: Index) {
self.tags[i.index()] = Tag::DeclRef;
self.datas[i.index()] = Data::index(decl);
}
fn push_struct_decl<I: IntoIterator<Item = (intern::Index, Index)>>(
&mut self,
name: intern::Index,
flags: StructFlags,
fields: I,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
let (offset, _) = self.extend_extra([flags.pack()]);
let (names, types) = fields
.into_iter()
.map(|(name, ty)| (name.into_u32(), ty.into_u32()))
.unzip::<_, _, Vec<_>, Vec<_>>();
self.extend_extra(types);
self.extend_extra(names);
self.set_tag_data_source_loc(
i,
Tag::StructDecl,
Data::intern_and_extra_offset(name, offset),
loc,
);
i
}
fn push_field_decl(&mut self, name: intern::Index, ty: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::FieldDecl, Data::index_and_intern(ty, name), loc);
i
}
fn push_field_access(
&mut self,
expr: Index,
name: intern::Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::FieldAccess, Data::index_and_intern(expr, name), loc);
i
}
fn push_interend_type(&mut self, ty: intern::Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::InternedType, Data::intern(ty), loc);
i
}
fn push_array_type(
&mut self,
length_expr: Index,
pointer_ty: Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(
i,
Tag::ArrayType,
Data::two_indices(length_expr, pointer_ty),
loc,
);
i
}
fn push_pointer_type(&mut self, ty: Index, flags: PointerFlags, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(
i,
Tag::PointerType,
Data::index_and_extra_offset(ty, flags.pack() as u32),
loc,
);
i
}
fn push_type_ref_unresolved(
&mut self,
scope: Index,
ident: intern::Index,
loc: SourceLocation,
) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(
i,
Tag::TypeDeclRefUnresolved,
Data::index_and_intern(scope, ident),
loc,
);
i
}
fn resolve_type_ref(&mut self, i: Index, decl: Index) {
self.tags[i.index()] = Tag::TypeDeclRef;
self.datas[i.index()] = Data::index(decl);
}
fn push_expr_stmt(&mut self, expr: Index) -> Index {
let i = self.reserve_node();
let loc = self.get_loc(expr);
self.set_tag_data_source_loc(i, Tag::ExprStmt, Data::index(expr), loc);
i
}
fn push_constant(&mut self, value: intern::Index, ty: Index, loc: SourceLocation) -> Index {
let i = self.reserve_node();
self.set_tag_data_source_loc(i, Tag::Constant, Data::index_and_intern(ty, value), loc);
i
}
fn extend_extra_by_indices<I: IntoIterator<Item = Index>>(&mut self, indices: I) -> (u32, u32) {
self.extend_extra(indices.into_iter().map(|i| i.0.get()))
}
fn extend_extra<I: IntoIterator<Item = u32>>(&mut self, words: I) -> (u32, u32) {
let i = self.extra.len() as u32;
self.extra.extend(words);
(i, self.extra.len() as u32)
}
fn set_tag_data_source_loc(&mut self, index: Index, tag: Tag, data: Data, loc: SourceLocation) {
self.tags[index.index()] = tag;
self.datas[index.index()] = data;
self.source_locs[index.index()] = loc;
}
}
struct Children(Vec<Index>);
impl Display for Children {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
if let Some((last, rest)) = self.0.split_last() {
for i in rest {
write!(f, "{i}, ")?;
}
write!(f, "{last}")?;
}
write!(f, "]")
}
}
type TypeCache = BTreeMap<Index, intern::Index>;
// type ComptimeCache = BTreeMap<Index, bool>;
#[derive(Debug, Default)]
struct ComptimeCache {
inner: BTreeMap<Index, bool>,
// this is (a,b) where b dominates a
// meaning:
// when a is marked as runtime, b can be updated to be runtime as well.
dependencies: BTreeMap<Index, Index>,
}
impl ComptimeCache {
fn get(&self, key: &Index) -> Option<bool> {
self.inner.get(key).cloned()
}
fn insert(&mut self, key: Index, value: bool) {
self.inner.insert(key, value);
if !value {
self.set_runtime(key);
}
}
fn mark_as_dominated_by(&mut self, a: Index, b: Index) {
self.dependencies.insert(a, b);
}
fn set_runtime(&mut self, key: Index) {
self.inner.insert(key, false);
if let Some(&dom) = self.dependencies.get(&key) {
self.set_runtime(dom);
}
}
}
impl Ast {
fn get_type_of_node(
&self,
ip: &InternPool,
cache: &mut TypeCache,
index: Index,
) -> intern::Index {
if let Some(ty) = cache.get(&index) {
return *ty;
}
let void = ip.get_void_type();
let tag = self.tags[index.index()];
let data = self.datas[index.index()];
let ty = match tag {
Tag::ArgumentList
| Tag::ExprStmt
| Tag::ReturnExprStmt
| Tag::Block
| Tag::ParameterList
| Tag::File => void,
Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => {
let (_, b) = data.as_extra_range();
self.get_type_of_node(ip, cache, Index::new(self.extra[b - 1]))
}
Tag::VarDecl | Tag::MutVarDecl => {
let (a, b) = data.as_extra_range();
self.get_type_of_node(ip, cache, Index::new(self.extra[a + 1]))
}
Tag::GlobalDecl => {
let (_, a) = data.as_intern_and_extra_offset();
self.get_type_of_node(ip, cache, Index::new(self.extra[a]))
}
Tag::FunctionDecl => self.get_type_of_node(ip, cache, data.as_two_indices().0),
Tag::FunctionProto => {
let (_, i) = data.as_intern_and_extra_offset();
let return_type = { self.datas[self.extra[i] as usize].as_intern() };
let parameters = {
let (a, b) = self.datas[self.extra[i + 1] as usize].as_extra_range();
self.extra[a..b].iter().map(|&i| {
// i is index to a parameter, a parameter is (index, intern)
let ty = self.datas[i as usize].as_index_intern().0;
self.datas[ty.index()].as_intern()
})
};
ip.try_get_function_type(return_type, parameters).unwrap()
}
Tag::BlockTrailingExpr => {
let (a, b) = data.as_extra_range();
self.get_type_of_node(ip, cache, Index::new(self.extra[b - 1]))
}
Tag::CallExpr => {
let (expr, _args) = data.as_two_indices();
let fn_ty = self.get_type_of_node(ip, cache, expr);
if let intern::Key::FunctionType { return_type, .. } = ip.get_key(fn_ty) {
return_type
} else {
eprintln!("lhs of call expr is not a function!");
void
}
}
Tag::Argument => self.get_type_of_node(ip, cache, data.as_index()),
Tag::NamedArgument => {
let (a, _) = data.as_index_intern();
self.get_type_of_node(ip, cache, a)
}
Tag::ExplicitCast => {
let (_, a) = data.as_two_indices();
self.get_type_of_node(ip, cache, a)
}
Tag::FieldAccess => {
let (ty_expr, name) = data.as_index_intern();
let ty = self.get_type_of_node(ip, cache, ty_expr);
match ip.get_key(ty) {
intern::Key::PointerType { pointee, .. }
if let intern::Key::StructType { fields, .. } = ip.get_key(pointee) =>
{
fields
.iter()
.cloned()
.find(|(n, _)| n == &name)
.map(|(_, t)| t)
.unwrap_or(void)
}
intern::Key::StructType { fields, .. } => fields
.iter()
.cloned()
.find(|(n, _)| n == &name)
.map(|(_, t)| t)
.unwrap_or(void),
_ => {
unimplemented!()
}
}
}
Tag::Deref => {
let ty = self.get_type_of_node(ip, cache, data.as_index());
if let intern::Key::PointerType { pointee, .. } = ip.get_key(ty) {
pointee
} else {
eprintln!("lhs of deref is not a pointer!");
void
}
}
Tag::SubscriptExpr => {
let ty = self.get_type_of_node(ip, cache, data.as_two_indices().0);
match ip.get_key(ty) {
intern::Key::PointerType { pointee, .. }
| intern::Key::ArrayType { pointee, .. } => pointee,
_ => {
eprintln!("lhs of subscript is not an array or pointer!");
void
}
}
}
Tag::AddressOf => {
let ty = self.get_type_of_node(ip, cache, data.as_index());
// TODO: find out of the expression is const, volatile for flags
ip.try_get_pointer_type(ty, None).unwrap()
}
Tag::Not | Tag::Negate => self.get_type_of_node(ip, cache, data.as_index()),
Tag::Or
| Tag::And
| Tag::BitOr
| Tag::BitXOr
| Tag::BitAnd
| Tag::Eq
| Tag::NEq
| Tag::Lt
| Tag::Gt
| Tag::Le
| Tag::Ge
| Tag::Shl
| Tag::Shr
| Tag::Add
| Tag::Sub
| Tag::Mul
| Tag::Div
| Tag::Rem => self.get_type_of_node(ip, cache, data.as_two_indices().0),
Tag::IfExpr => ip.get_bool_type(), // really?
Tag::IfElseExpr => {
let (_, b) = data.as_index_and_extra_offset();
let if_ = Index::new(self.extra[b]);
self.get_type_of_node(ip, cache, if_)
}
Tag::Constant | Tag::Parameter => {
self.get_type_of_node(ip, cache, data.as_index_intern().0)
}
Tag::DeclRef => self.get_type_of_node(ip, cache, data.as_index()),
Tag::StructDecl => {
let (name, _) = data.as_intern_and_extra_offset();
ip.try_get_struct_type(name, index).unwrap()
}
Tag::Assign
| Tag::Root
| Tag::DeclRefUnresolved
| Tag::Error
| Tag::Undefined
| Tag::ReturnStmt => void,
Tag::FieldDecl => self.get_type_of_node(ip, cache, data.as_index_intern().0),
Tag::InternedType => data.as_intern(),
Tag::TypeDeclRef | Tag::TypeDeclRefUnresolved | Tag::PointerType | Tag::ArrayType => {
unreachable!()
}
};
cache.insert(index, ty);
ty
}
fn get_node_children(&self, index: Index) -> Vec<Index> {
let tag = self.tags[index.index()];
let data = self.datas[index.index()];
match tag {
Tag::File => {
let (a, b) = data.as_extra_range();
self.extra[a..b].iter().map(|&i| Index::new(i)).collect()
}
Tag::FunctionProto => {
let (_, i) = data.as_intern_and_extra_offset();
self.extra[i..=i + 1]
.iter()
.map(|&i| Index::new(i))
.collect()
}
Tag::FunctionDecl => {
let (a, b) = data.as_two_indices();
vec![a, b]
}
Tag::ParameterList => {
let (a, b) = data.as_extra_range();
self.extra[a..b].iter().map(|&i| Index::new(i)).collect()
}
Tag::Block | Tag::BlockTrailingExpr => {
let (a, b) = data.as_extra_range();
self.extra[a..b].iter().map(|&i| Index::new(i)).collect()
}
Tag::ExprStmt | Tag::ReturnExprStmt => {
let a = data.as_index();
vec![a]
}
Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => {
let (a, b) = data.as_extra_range();
self.extra[a + 1..b]
.iter()
.map(|&i| Index::new(i))
.collect()
}
Tag::GlobalDecl => {
let (_, offset) = data.as_intern_and_extra_offset();
self.extra[offset..=offset + 1]
.iter()
.map(|&i| Index::new(i))
.collect()
}
Tag::CallExpr | Tag::ExplicitCast => {
let (a, b) = data.as_two_indices();
vec![a, b]
}
Tag::ArgumentList => {
let (a, b) = data.as_extra_range();
self.extra[a..b].iter().map(|&i| Index::new(i)).collect()
}
Tag::Argument => {
let a = data.as_index();
vec![a]
}
Tag::FieldDecl | Tag::FieldAccess | Tag::NamedArgument => {
let (a, _) = data.as_index_intern();
vec![a]
}
Tag::Deref | Tag::AddressOf | Tag::Not | Tag::Negate => {
let a = data.as_index();
vec![a]
}
Tag::Or
| Tag::And
| Tag::BitOr
| Tag::BitXOr
| Tag::BitAnd
| Tag::Eq
| Tag::NEq
| Tag::Lt
| Tag::Gt
| Tag::Le
| Tag::Ge
| Tag::Shl
| Tag::Shr
| Tag::Add
| Tag::Sub
| Tag::Mul
| Tag::Div
| Tag::Rem
| Tag::Assign
| Tag::SubscriptExpr
| Tag::ArrayType
| Tag::IfExpr => {
let (a, b) = data.as_two_indices();
vec![a, b]
}
Tag::IfElseExpr => {
let (a, b) = data.as_index_and_extra_offset();
let if_ = Index::new(self.extra[b]);
let else_ = Index::new(self.extra[b + 1]);
vec![a, if_, else_]
}
Tag::PointerType => {
let (a, _) = data.as_index_and_extra_offset();
vec![a]
}
Tag::StructDecl => {
let (a, offset) = data.as_intern_and_extra_offset();
let flags = StructFlags::unpack(self.extra[offset]);
self.extra[offset + 1..(offset + 1 + flags.num_fields as usize)]
.iter()
.map(|&i| Index::new(i))
.collect()
}
Tag::InternedType
| Tag::Root
| Tag::TypeDeclRefUnresolved
| Tag::DeclRefUnresolved
| Tag::Error
| Tag::Undefined
| Tag::TypeDeclRef
| Tag::DeclRef
| Tag::ReturnStmt => vec![],
Tag::Parameter | Tag::Constant => {
let (a, _) = data.as_index_intern();
vec![a]
}
Tag::VarDecl | Tag::MutVarDecl => {
let (a, _) = data.as_extra_range();
vec![Index::new(self.extra[a + 1])]
}
}
}
fn is_node_comptime_evaluable(&self, cache: &mut ComptimeCache, index: Index) -> bool {
if let Some(a) = cache.get(&index) {
a
} else {
let tag = self.tags[index.index()];
let data = self.datas[index.index()];
let children = self.get_node_children(index);
let are_children_comptime = |this: &Self, cache: &mut ComptimeCache| {
children
.iter()
.all(|&i| this.is_node_comptime_evaluable(cache, i))
};
let is_comptime = match tag {
Tag::Parameter => false,
Tag::Block | Tag::BlockTrailingExpr => are_children_comptime(self, cache),
Tag::Constant => true,
Tag::ReturnStmt => true,
Tag::ReturnExprStmt => are_children_comptime(self, cache),
Tag::VarDecl | Tag::MutVarDecl => true,
Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => {
are_children_comptime(self, cache)
}
Tag::GlobalDecl => true,
Tag::StructDecl => true,
Tag::FieldDecl => true,
Tag::DeclRef => self.tags[data.as_index().index()] == Tag::GlobalDecl,
Tag::InternedType | Tag::PointerType | Tag::ArrayType | Tag::TypeDeclRef => true,
Tag::CallExpr => false,
Tag::FieldAccess => {
let parent = data.as_index_intern().0;
cache.mark_as_dominated_by(index, parent);
self.is_node_comptime_evaluable(cache, parent)
}
Tag::ArgumentList => are_children_comptime(self, cache),
Tag::Argument => self.is_node_comptime_evaluable(cache, data.as_index()),
Tag::NamedArgument => {
self.is_node_comptime_evaluable(cache, data.as_index_intern().0)
}
Tag::ExplicitCast => {
self.is_node_comptime_evaluable(cache, data.as_two_indices().0)
}
Tag::Deref | Tag::AddressOf => false,
Tag::Not
| Tag::Negate
| Tag::Or
| Tag::And
| Tag::BitOr
| Tag::BitXOr
| Tag::BitAnd
| Tag::Eq
| Tag::NEq
| Tag::Lt
| Tag::Gt
| Tag::Le
| Tag::Ge
| Tag::Shl
| Tag::Shr
| Tag::Add
| Tag::Sub
| Tag::Mul
| Tag::Div
| Tag::SubscriptExpr
| Tag::Rem => are_children_comptime(self, cache),
Tag::Assign => {
let (left, _) = data.as_two_indices();
cache.mark_as_dominated_by(index, left);
are_children_comptime(self, cache)
}
Tag::IfExpr | Tag::IfElseExpr => are_children_comptime(self, cache),
Tag::Root
| Tag::File
| Tag::FunctionProto
| Tag::FunctionDecl
| Tag::ParameterList
| Tag::ExprStmt
| Tag::DeclRefUnresolved
| Tag::TypeDeclRefUnresolved
| Tag::Error
| Tag::Undefined => false,
};
cache.insert(index, is_comptime);
is_comptime
}
}
// fn comptime_value_of_node(
// &self,
// ip: &InternPool,
// pointer_bits: u16,
// cache: &mut TypeCache,
// index: Index,
// ) -> crate::comptime::ComptimeNumber {
// let tag = self.tags[index.index()];
// let data = self.datas[index.index()];
// match tag {
// Tag::Root => todo!(),
// Tag::File => todo!(),
// Tag::FunctionProto => todo!(),
// Tag::FunctionDecl => todo!(),
// Tag::ParameterList => todo!(),
// Tag::Parameter => todo!(),
// Tag::Block => todo!(),
// Tag::BlockTrailingExpr => {
// let (a, b) = data.as_extra_range();
// if a != b {
// self.comptime_value_of_node(
// ip,
// pointer_bits,
// cache,
// Index::new(self.extra[b - 1]),
// )
// } else {
// None
// }
// }
// Tag::Constant => {
// let (ty, value) = data.as_index_intern();
// let ty = self.get_type_of_node(ip, cache, ty);
// interned_type_and_value_to_comptime_number(ip, pointer_bits, ty, value)
// }
// Tag::ExprStmt => todo!(),
// Tag::ReturnStmt => todo!(),
// Tag::ReturnExprStmt => todo!(),
// Tag::VarDecl => todo!(),
// Tag::MutVarDecl => todo!(),
// Tag::VarDeclAssignment => todo!(),
// Tag::MutVarDeclAssignment => todo!(),
// Tag::GlobalDecl => todo!(),
// Tag::StructDecl => todo!(),
// Tag::FieldDecl => todo!(),
// Tag::DeclRef => todo!(),
// Tag::DeclRefUnresolved => todo!(),
// Tag::InternedType => todo!(),
// Tag::TypeDeclRef => todo!(),
// Tag::TypeDeclRefUnresolved => todo!(),
// Tag::PointerType => todo!(),
// Tag::ArrayType => todo!(),
// Tag::CallExpr => todo!(),
// Tag::FieldAccess => todo!(),
// Tag::ArgumentList => todo!(),
// Tag::Argument => todo!(),
// Tag::NamedArgument => todo!(),
// Tag::ExplicitCast => todo!(),
// Tag::Deref => todo!(),
// Tag::AddressOf => todo!(),
// Tag::Not => todo!(),
// Tag::Negate => todo!(),
// Tag::Or => todo!(),
// Tag::And => todo!(),
// Tag::BitOr => todo!(),
// Tag::BitXOr => todo!(),
// Tag::BitAnd => todo!(),
// Tag::Eq => todo!(),
// Tag::NEq => todo!(),
// Tag::Lt => todo!(),
// Tag::Gt => todo!(),
// Tag::Le => todo!(),
// Tag::Ge => todo!(),
// Tag::Shl => todo!(),
// Tag::Shr => todo!(),
// Tag::Add => todo!(),
// Tag::Sub => todo!(),
// Tag::Mul => todo!(),
// Tag::Div => todo!(),
// Tag::Rem => todo!(),
// Tag::Assign => todo!(),
// Tag::SubscriptExpr => todo!(),
// Tag::IfExpr => todo!(),
// Tag::IfElseExpr => todo!(),
// Tag::Error => todo!(),
// Tag::Undefined => todo!(),
// }
// }
}
fn interned_type_and_value_to_comptime_number(
ip: &InternPool,
pointer_bits: u16,
ty: intern::Index,
val: intern::Index,
) -> crate::comptime::ComptimeNumber {
use crate::ast::IntegralType;
use crate::comptime::*;
let ty_key = ip.get_key(ty);
match ty_key {
intern::Key::SIntType { bits } | intern::Key::UIntType { bits } => {
let ty = IntegralType::new(false, bits);
match ip.get_key(val) {
intern::Key::SIntSmall { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
}),
intern::Key::UIntSmall { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
}),
intern::Key::SInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
}),
intern::Key::UInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
}),
intern::Key::PositiveInt { bigint } => {
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
}
intern::Key::NegativeInt { bigint } => {
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
}
_ => {
unreachable!()
}
}
}
intern::Key::SimpleType { ty } => match ty {
intern::SimpleType::F32 => match ip.get_key(val) {
intern::Key::F32 { bits } => {
ComptimeNumber::Floating(ComptimeFloat::Binary32(bits))
}
_ => {
unreachable!()
}
},
intern::SimpleType::F64 => match ip.get_key(val) {
intern::Key::F64 { bits } => {
ComptimeNumber::Floating(ComptimeFloat::Binary64(bits))
}
_ => {
unreachable!()
}
},
intern::SimpleType::Bool => match ip.get_key(val) {
intern::Key::TrueValue => ComptimeNumber::Bool(true),
intern::Key::FalseValue => ComptimeNumber::Bool(false),
_ => unreachable!(),
},
intern::SimpleType::Void => todo!(),
intern::SimpleType::USize | intern::SimpleType::ISize => {
let ty = IntegralType::new(
matches!(
ty_key,
intern::Key::SimpleType {
ty: intern::SimpleType::ISize
}
),
pointer_bits,
);
match ip.get_key(val) {
intern::Key::SIntSmall { bits } => {
ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
})
}
intern::Key::UIntSmall { bits } => {
ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
})
}
intern::Key::SInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
}),
intern::Key::UInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
bits: bits as _,
ty,
}),
intern::Key::PositiveInt { bigint } => {
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
}
intern::Key::NegativeInt { bigint } => {
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
}
_ => {
unreachable!()
}
}
}
intern::SimpleType::ComptimeInt => {
let bigint = match ip.get_key(val) {
intern::Key::SIntSmall { bits } => {
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
}
intern::Key::UIntSmall { bits } => {
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
}
intern::Key::SInt64 { bits } => {
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
}
intern::Key::UInt64 { bits } => {
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
}
intern::Key::PositiveInt { bigint } | intern::Key::NegativeInt { bigint } => {
bigint
}
_ => {
unreachable!()
}
};
ComptimeNumber::Integral(ComptimeInt::Comptime(bigint))
}
},
_ => {
unreachable!()
}
}
}
pub struct AstRenderer<'a> {
ast: &'a Ast,
#[allow(dead_code)]
syms: &'a crate::symbol_table::syms2::Symbols,
ip: &'a InternPool,
scopes: Vec<Index>,
cache: TypeCache,
comptime_cache: ComptimeCache,
}
impl<'a> AstRenderer<'a> {
pub fn new(
ast: &'a Ast,
ip: &'a InternPool,
syms: &'a crate::symbol_table::syms2::Symbols,
) -> Self {
Self {
ast,
syms,
ip,
scopes: Vec::new(),
cache: TypeCache::new(),
comptime_cache: ComptimeCache::default(),
}
}
fn render_node<W: core::fmt::Write>(
&mut self,
w: &mut W,
indent: u32,
node: Index,
) -> core::fmt::Result {
let tag = self.ast.tags[node.index()];
let loc = self.ast.source_locs[node.index()];
match tag {
Tag::File | Tag::FunctionDecl | Tag::Block | Tag::BlockTrailingExpr => {
self.scopes.push(node);
}
_ => {}
}
let children = Children(self.ast.get_node_children(node));
let ty = self.ast.get_type_of_node(self.ip, &mut self.cache, node);
let is_comptime = self
.ast
.is_node_comptime_evaluable(&mut self.comptime_cache, node);
writeln_indented!(
indent * 2,
w,
"{node} {}({ty}) = ({loc}) {tag:?} {children}",
if is_comptime { "CONST " } else { "" }
)?;
for child in children.0 {
self.render_node(w, indent + 1, child)?;
}
match tag {
Tag::File | Tag::FunctionDecl | Tag::Block | Tag::BlockTrailingExpr => {
self.scopes.pop();
}
_ => {}
}
Ok(())
}
fn render<W: core::fmt::Write>(&mut self, w: &mut W) -> core::fmt::Result {
for file in self.ast.get_root_file_indices() {
self.render_node(w, 0, file)?;
}
Ok(())
}
}
pub mod ast_gen {
use intern::{PointerFlags, SimpleType};
use itertools::Itertools;
use num_bigint::{BigInt, BigUint};
use crate::{
common::from_lo_hi_dwords,
comptime,
lexer::{Radix, TokenItem, TokenIterator},
symbol_table::syms2::SymbolKind,
tokens::PRECEDENCE_MAP,
variant,
};
use super::*;
#[derive(Debug)]
pub struct ErrorInfo {
error: ParseError,
loc: SourceLocation,
}
#[derive(Debug)]
pub struct Parser {
pub ast: Ast,
pub intern: intern::InternPool,
pub syms: crate::symbol_table::syms2::Symbols,
scopes: Vec<Index>,
pub errors: Vec<ErrorInfo>,
}
type ParseResult<T> = core::result::Result<T, ErrorInfo>;
impl Display for Parser {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.display().render(f)
}
}
impl Parser {
pub fn new() -> Parser {
Self {
ast: Ast::new(),
intern: intern::InternPool::create(),
syms: crate::symbol_table::syms2::Symbols::new(),
scopes: Vec::new(),
errors: Vec::new(),
}
}
pub fn display(&self) -> AstRenderer<'_> {
AstRenderer::new(&self.ast, &self.intern, &self.syms)
}
pub fn fold_and_typecheck(&mut self) {
enum Asdf {
Pre(Index),
Post(Index),
}
let mut nodes = self.ast.get_root_file_indices().collect::<Vec<_>>();
let mut cache = TypeCache::new();
}
pub fn intern_types(&mut self) {
let mut nodes = self
.ast
.get_root_file_indices()
.map(|i| A::PushChildren(i))
.collect::<Vec<_>>();
enum A {
PushChildren(Index),
PopSelf(Index),
}
while let Some(node) = nodes.pop() {
match node {
A::PushChildren(i) => {
nodes.push(A::PopSelf(i));
nodes.extend(
self.ast
.get_node_children(i)
.into_iter()
.map(|i| A::PushChildren(i)),
);
}
A::PopSelf(i) => {
let tag = self.ast.tags[i.index()];
let data = self.ast.datas[i.index()];
match tag {
Tag::ArrayType => {
let (length, pointee) = data.as_two_indices();
let pointee = self.ast.datas[pointee.index()].as_intern();
variant!( self.intern.get_key(pointee) => intern::Key::PointerType { pointee, flags });
// get interened value from constant node
let length = {
let value = self.ast.datas[length.index()].as_index_intern().1;
match self.intern.get_key(value) {
intern::Key::SIntSmall { bits } => bits as u32,
intern::Key::UIntSmall { bits } => bits as u32,
intern::Key::SInt64 { bits } => bits as u32,
intern::Key::UInt64 { bits } => bits as u32,
intern::Key::NegativeInt { bigint }
| intern::Key::PositiveInt { bigint } => {
bigint.iter_u32_digits().next().unwrap_or(0)
}
_ => 0,
}
};
let ty = self.intern.get_array_type(pointee, Some(flags), length);
self.ast.tags[i.index()] = Tag::InternedType;
self.ast.datas[i.index()] = Data::intern(ty);
}
Tag::PointerType => {
let (pointee, flags) = data.as_index_and_extra_offset();
let pointee = self.ast.datas[pointee.index()].as_intern();
let ty = self.intern.get_pointer_type(
pointee,
Some(PointerFlags::unpack(flags as u8)),
);
self.ast.tags[i.index()] = Tag::InternedType;
self.ast.datas[i.index()] = Data::intern(ty);
}
Tag::TypeDeclRef => {
let decl = data.as_index();
let (name, _) =
self.ast.datas[decl.index()].as_intern_and_extra_offset();
let ty = self.intern.get_struct_type(name, decl);
self.ast.tags[i.index()] = Tag::InternedType;
self.ast.datas[i.index()] = Data::intern(ty);
}
Tag::FunctionProto => {
let (_, i) = data.as_intern_and_extra_offset();
let return_type = self.ast.get_type_of_node(
&self.intern,
&mut TypeCache::new(),
Index::new(self.ast.extra[i]),
);
let parameters = {
let (a, b) = self.ast.datas[self.ast.extra[i + 1] as usize]
.as_extra_range();
self.ast.extra[a..b].iter().map(|&i| {
// i is index to a parameter, a parameter is (index, intern)
let ty = self.ast.datas[i as usize].as_index_intern().0;
self.ast.datas[ty.index()].as_intern()
})
};
self.intern.get_function_type(return_type, parameters);
}
Tag::StructDecl => {
let (name, offset) = data.as_intern_and_extra_offset();
let flags = StructFlags::unpack(self.ast.extra[offset]);
let types = (offset + 1)..(offset + 1 + flags.num_fields as usize);
let names = (offset + 1 + flags.num_fields as usize)
..(offset + 1 + flags.num_fields as usize * 2);
let types = self.ast.extra[types]
.iter()
.map(|&i| Index::new(i))
.map(|i| self.ast.datas[i.index()].as_intern());
let names = self.ast.extra[names].iter().map(|&i| intern::Index(i));
self.intern.insert_or_replace_struct_type(
name,
i,
flags.packed,
flags.c_like,
names.zip(types),
);
}
_ => {}
}
}
}
}
}
pub fn resolve_decl_refs(&mut self) {
let mut nodes = self.ast.get_root_file_indices().collect::<Vec<_>>();
let mut scopes = Vec::new();
while let Some(node) = nodes.pop() {
match self.ast.tags[node.index()] {
Tag::File | Tag::FunctionDecl | Tag::Block | Tag::BlockTrailingExpr => {
scopes.push(node);
}
_ => {}
}
let children = self.ast.get_node_children(node);
nodes.extend(children.into_iter().rev());
match self.ast.tags[node.index()] {
Tag::File | Tag::FunctionDecl | Tag::Block | Tag::BlockTrailingExpr => {
scopes.pop();
}
Tag::TypeDeclRefUnresolved => {
let (scope, name) = self.ast.datas[node.index()].as_index_intern();
// look in my_scope
if let Some(decl) = self.syms.find_type_symbol(
scope,
name,
self.ast.source_locs[node.index()],
) {
self.ast.resolve_type_ref(node, decl)
};
}
Tag::DeclRefUnresolved => {
let (scope, name) = self.ast.datas[node.index()].as_index_intern();
// look in my_scope
if let Some(decl) =
self.syms
.find_symbol(scope, name, self.ast.source_locs[node.index()])
{
self.ast.resolve_decl_ref(node, decl)
};
}
_ => {}
}
}
}
fn current_scope(&self) -> Index {
self.scopes.last().cloned().unwrap()
}
fn parse_ident(&mut self, tokens: &mut TokenIterator) -> Result<intern::Index, ErrorInfo> {
let ident = tokens.expect_token(Token::Ident).map_err(|_| ErrorInfo {
error: ParseError::ExpectedIdent,
loc: tokens.current_source_location(),
})?;
let name = self.intern.get_or_insert(intern::Key::String {
str: ident.lexeme(),
});
Ok(name)
}
fn parse_pointer(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
tokens.eat_token(Token::Star).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Star),
loc: tokens.current_source_location(),
})?;
let &[cnst, vol, noalias] =
&tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3]
else {
unreachable!()
};
let pointee = self.parse_type(tokens)?;
Ok(self
.ast
.push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc))
}
/// [LENGTH]const? volatile? noalias? TYPE
fn parse_array_type(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let length_expr = self.parse_bracketed(tokens, |this, tokens| {
let next = tokens.peek_token().ok_or(ErrorInfo {
error: ParseError::UnexpectedEndOfTokens,
loc: tokens.current_source_location(),
})?;
match next.token() {
Token::IntegerBinConstant
| Token::IntegerHexConstant
| Token::IntegerOctConstant
| Token::IntegerConstant => {
_ = tokens.next();
Ok(this.parse_integral_constant(&next, next.source_location()))
}
_ => Err(ErrorInfo {
error: ParseError::ExpectedConstantLiteral,
loc: tokens.current_source_location(),
}),
}
})?;
let &[cnst, vol, noalias] =
&tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3]
else {
unreachable!()
};
let pointee = self.parse_type(tokens)?;
let pointer =
self.ast
.push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc);
Ok(self.ast.push_array_type(length_expr, pointer, loc))
}
fn parse_simple_type(&mut self, token: Token) -> Option<intern::Index> {
match token {
Token::Void => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
ty: SimpleType::Void,
})),
Token::Bool => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
ty: SimpleType::Bool,
})),
Token::F32 => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
ty: SimpleType::F32,
})),
Token::F64 => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
ty: SimpleType::F64,
})),
Token::USize => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
ty: SimpleType::USize,
})),
Token::ISize => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
ty: SimpleType::ISize,
})),
_ => None,
}
}
fn try_parse_integral_type(
&mut self,
typename: &str,
) -> Result<Option<intern::Index>, ParseError> {
let mut iter = typename.chars().peekable();
let signed = match iter.next() {
Some('u') => false,
Some('i') => true,
_ => {
return Ok(None);
}
};
// need 1 digit for an integral type
if iter.peek().map(|&c| crate::common::is_digit(c)) != Some(true) {
return Ok(None);
}
// need no nondigits after digits
if iter
.clone()
.skip_while(|&c| crate::common::is_digit(c))
.next()
.is_some()
{
return Ok(None);
}
let mut bits = 0u16;
loop {
let Some(digit) = iter.next().map(|c| c as u8 - b'0') else {
break;
};
match bits
.checked_mul(10)
.and_then(|bits| bits.checked_add(digit as u16))
{
Some(val) => {
bits = val;
}
None => {
// this IS an integral type, but it is bigger than u/i65535
return Err(ParseError::IntegralTypeTooWide);
}
}
}
Ok(Some(self.intern.get_int_type(signed, bits)))
}
fn parse_integral_constant_inner(
&mut self,
item: &TokenItem,
) -> (intern::Index, intern::Index) {
let radix = Radix::from_token(item.token()).unwrap();
let mut chars = item.lexeme().char_indices();
match radix {
Radix::Dec => {}
_ => {
_ = chars.advance_by(2);
}
}
let digits = chars
.take_while_ref(|&(_, c)| radix.is_digit()(c) || c == '_')
.filter(|&(_, c)| c != '_')
.map(|(_, c)| c)
.collect::<Vec<_>>();
let value = comptime::bigint::parse_bigint(digits.into_iter(), radix);
let ty = match chars.clone().next() {
Some((i, 'u')) | Some((i, 'i')) => self
.try_parse_integral_type(&item.lexeme()[i..])
.expect("invalid integral type??"),
_ => None,
};
let interned = match value.len() {
..1 => {
let bits = value.get(0).cloned().unwrap_or(0);
self.intern.get_or_insert(intern::Key::UIntSmall { bits })
}
..2 => {
let lo = value.get(0).cloned().unwrap_or(0);
let hi = value.get(1).cloned().unwrap_or(0);
let bits = from_lo_hi_dwords(lo, hi);
self.intern.get_or_insert(intern::Key::UInt64 { bits })
}
_ => {
let bigint = BigInt::from_biguint(num_bigint::Sign::Plus, BigUint::new(value));
self.intern
.get_or_insert(intern::Key::PositiveInt { bigint })
}
};
let ty = ty.unwrap_or(self.intern.get_comptime_int_type());
(interned, ty)
}
fn parse_integral_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index {
let (interned, ty) = self.parse_integral_constant_inner(item);
let ty = self.ast.push_interend_type(ty, loc);
return self.ast.push_constant(interned, ty, loc);
}
fn parse_floating_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index {
let lexeme = item.lexeme();
let lexeme = lexeme
.strip_suffix("f32")
.map(|l| (l, self.intern.get_f32_type()))
.unwrap_or(
lexeme
.strip_suffix("f64")
.map(|l| (l, self.intern.get_f64_type()))
.unwrap_or((lexeme, self.intern.get_f64_type())),
);
let bits = if lexeme.1 == self.intern.get_f32_type() {
self.intern.get_or_insert(intern::Key::F32 {
bits: lexeme.0.parse::<f32>().unwrap(),
})
} else {
self.intern.get_or_insert(intern::Key::F64 {
bits: lexeme.0.parse::<f64>().unwrap(),
})
};
let ty = self.ast.push_interend_type(lexeme.1, loc);
return self.ast.push_constant(bits, ty, loc);
}
/// TYPE <-
/// * TYPE
/// IDENTIFIER
/// SIMPLE_TYPE
/// [ TYPE ; CONSTANT_EXPR ]
/// INTEGRAL_TYPE // u[0..65535] | i[0..65535]
fn parse_type(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
match tokens
.peek_token()
.ok_or(ErrorInfo {
error: ParseError::ExpectedTypeName,
loc: tokens.current_source_location(),
})?
.token()
{
Token::Star => self.parse_pointer(tokens),
Token::OpenSquareBracket => self.parse_array_type(tokens),
Token::Ident => {
let token = tokens.next().unwrap();
match self
.try_parse_integral_type(token.lexeme())
.map_err(|error| ErrorInfo {
error,
loc: token.source_location(),
})? {
Some(int) => Ok(self.ast.push_interend_type(int, loc)),
None => {
let name = self.intern.get_or_insert(intern::Key::String {
str: token.lexeme(),
});
// TODO: this will cause issues with redefinitions of types with the same name
// and actually, make type into a proper node of the ast
Ok(self
.ast
.push_type_ref_unresolved(self.current_scope(), name, loc))
}
}
}
token => {
let ty = self.parse_simple_type(token).ok_or(ErrorInfo {
error: ParseError::ExpectedTypeName,
loc: tokens.current_source_location(),
})?;
_ = tokens.next();
Ok(self.ast.push_interend_type(ty, loc))
}
}
}
/// GLOBAL_DECL <-
/// const IDENTIFIER: TYPENAME = EXPR;
fn parse_const_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let err = 'blk: {
let loc = tokens.current_source_location();
let Some(_) = tokens.eat_token(Token::Const) else {
break 'blk ErrorInfo {
error: ParseError::ExpectedToken(Token::Const),
loc,
};
};
let ident = match self.parse_ident(tokens) {
Ok(i) => i,
Err(err) => {
break 'blk err;
}
};
let Some(_) = tokens.eat_token(Token::Colon) else {
return Err(ErrorInfo {
error: ParseError::ExpectedToken(Token::Colon),
loc,
});
};
let typename = match self.parse_type(tokens) {
Ok(i) => i,
Err(err) => {
break 'blk err;
}
};
let Some(_) = tokens.eat_token(Token::Equal) else {
break 'blk ErrorInfo {
error: ParseError::ExpectedToken(Token::Equal),
loc: tokens.current_source_location(),
};
};
let expr = match self.parse_expr(tokens) {
Ok(i) => i,
Err(err) => {
break 'blk err;
}
};
let Some(_) = tokens.eat_token(Token::Semi) else {
break 'blk ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
};
};
let decl = self.ast.push_global_decl(ident, typename, expr, loc);
self.syms
.insert_symbol(self.current_scope(), ident, SymbolKind::Const, decl);
return Ok(decl);
};
tokens.advance_past_semi().ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
Ok(self.ast.push_error(err.error, err.loc))
}
/// FUNCTION_PROTO <-
/// fn IDENTIFIER ()
/// fn IDENTIFIER () -> TYPENAME
/// fn IDENTIFIER ( PARAMETER_LIST ,? )
/// fn IDENTIFIER ( PARAMETER_LIST ,? ) -> TYPENAME
fn parse_fn_proto(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let _ = tokens.eat_token(Token::Fn).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Fn),
loc,
})?;
let ident = self.parse_ident(tokens)?;
let parameters = self.parse_parenthesised(tokens, |this, tokens| {
if tokens.is_next_token(Token::CloseParens) {
Ok(this.ast.push_parameter_list([], loc))
} else {
this.parse_parameter_list(tokens)
}
})?;
let return_type = if let Some(_) = tokens.eat_token(Token::MinusGreater) {
self.parse_type(tokens)?
} else {
self.ast.push_interend_type(
self.intern.get_void_type(),
tokens.current_source_location(),
)
};
return Ok(self.ast.push_fn_proto(ident, return_type, parameters, loc));
}
fn parse_fn_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let func = self.ast.reserve_node();
self.push_scope(func, intern::Index::invalid());
let proto = self.parse_fn_proto(tokens).map_err(|e| {
self.pop_scope();
e
})?;
let body = self.parse_block(tokens).map_err(|e| {
self.pop_scope();
e
})?;
self.pop_scope();
self.ast.set_fn_decl(func, proto, body, loc);
Ok(func)
}
/// FUNCTION_DECL <-
/// FUNCTION_PROTO BLOCK
fn parse_fn_decl(&mut self, tokens: &mut TokenIterator) -> Index {
match self.parse_fn_inner(tokens) {
Ok(i) => i,
Err(err) => {
self.find_next_fn_or_const(tokens);
self.push_error(err.error, err.loc)
}
}
}
/// RETURN_STATEMENT <-
/// return EXPRESSION? ;
fn parse_return_stmt(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
// SAFETY: function invariance
let ret = tokens.next().unwrap();
let loc = ret.source_location();
let expr = if tokens.eat_token(Token::Semi).is_some() {
self.ast.push_ret(None, loc)
} else {
match self.parse_expr(tokens) {
Ok(i) => {
tokens.eat_token(Token::Semi).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
self.ast.push_ret(Some(i), loc)
}
Err(err) => {
tokens.advance_past_semi().ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
self.push_error(err.error, err.loc)
}
}
};
Ok(expr)
}
/// VAR_DECL <-
/// (let | var) IDENTIFIER (: TYPENAME)? ;
/// (let | var) IDENTIFIER (: TYPENAME)? = EXPRESSION ;
fn parse_var_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
match self.parse_var_decl_inner(tokens) {
Ok(i) => {
_ = tokens.eat_token(Token::Semi).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
Ok(i)
}
Err(err) => {
tokens.advance_past_semi().ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
Ok(self.push_error(err.error, err.loc))
}
}
}
fn parse_var_decl_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
// SAFETY: function invariance
let let_or_var = tokens.next().unwrap();
let loc = let_or_var.source_location();
let is_let = let_or_var.token() == Token::Let;
let name = self.parse_ident(tokens)?;
let ty = if tokens.eat_token(Token::Colon).is_some() {
Some(self.parse_type(tokens)?)
} else {
None
};
let assignment = if tokens.eat_token(Token::Equal).is_some() {
Some(self.parse_expr(tokens)?)
} else {
None
};
let decl = self.ast.push_var_decl(is_let, name, ty, assignment, loc);
self.syms.insert_symbol(
self.current_scope(),
name,
SymbolKind::Local(tokens.current_source_location()),
decl,
);
Ok(decl)
}
fn parse_block_inner(
&mut self,
block: Index,
tokens: &mut TokenIterator,
) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let mut statements = Vec::new();
let trailing = loop {
if tokens.is_next_token(Token::CloseBrace) {
break None;
}
let next = tokens.peek_token().ok_or(ErrorInfo {
error: ParseError::UnexpectedEndOfTokens,
loc: tokens.current_source_location(),
})?;
if let Some(decl) = self.parse_constant_decls(tokens)? {
statements.push(decl);
} else {
match next.token() {
Token::Return => {
statements.push(self.parse_return_stmt(tokens)?);
}
Token::Var | Token::Let => {
statements.push(self.parse_var_decl(tokens)?);
}
_ => {
if self.is_statement(tokens) {
// expr -> statements
let expr = self
.parse_with_trailing_semi(tokens, |this, tokens| {
this.parse_expr(tokens)
})?;
statements.push(expr);
} else {
// expr -> trailing
let expr = self.parse_expr(tokens)?;
if !tokens.is_next_token(Token::CloseBrace) {
statements.push(self.push_error(
ParseError::ExpectedEndOfBlock,
tokens.current_source_location(),
));
} else {
break Some(expr);
}
}
}
}
}
};
self.ast.set_block(block, statements, trailing, loc);
Ok(block)
}
/// BLOCK <-
/// { STATEMENT* EXPRESSION? }
fn parse_block(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let block = self.parse_braced(tokens, |this, tokens| {
let block = this.ast.reserve_node();
this.push_scope(block, intern::Index::invalid());
let block_result = this.parse_block_inner(block, tokens);
this.pop_scope();
block_result
})?;
Ok(block)
}
/// PARAMETER_LIST <-
/// PARAMETER
/// PARAMETER_LIST , ARGUMENT
fn parse_parameter_list(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let mut params = Vec::new();
loop {
params.push(self.parse_parameter(tokens)?);
if !tokens.is_next_token(Token::Comma) {
break;
}
if tokens.is_next_token2(Token::CloseParens) {
break;
}
// skip comma
_ = tokens.next();
}
return Ok(self.ast.push_parameter_list(params, loc));
}
/// PARAMETER <-
/// IDENT : TYPENAME
fn parse_parameter(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let name = self.parse_ident(tokens)?;
let Some(_) = tokens.eat_token(Token::Colon) else {
return Err(ErrorInfo {
error: ParseError::ExpectedToken(Token::Colon),
loc,
});
};
let ty = self.parse_type(tokens)?;
let param = self.ast.push_parameter(name, ty, loc);
self.syms
.insert_symbol(self.current_scope(), name, SymbolKind::Local(loc), param);
return Ok(param);
}
/// ARGUMENT <-
/// IDENT : EXPR
/// EXPR
fn parse_argument(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let name = if tokens.is_next_token2(Token::Colon) && tokens.is_next_token(Token::Ident)
{
let name = self.parse_ident(tokens)?;
// we checked `is_next_token2`
_ = tokens.eat_token(Token::Colon).unwrap();
Some(name)
} else {
None
};
let expr = self.parse_expr(tokens)?;
let i = match name {
Some(name) => self.ast.push_named_argument(name, expr, loc),
None => self.ast.push_argument(expr, loc),
};
Ok(i)
}
/// ARGUMENT_LIST <-
/// ARGUMENT
/// ARGUMENT_LIST , ARGUMENT
fn parse_argument_list(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let mut args = Vec::new();
loop {
args.push(self.parse_argument(tokens)?);
if !tokens.is_next_token(Token::Comma) {
break;
}
if tokens.is_next_token2(Token::CloseParens) {
break;
}
// skip comma
_ = tokens.next();
}
return Ok(self.ast.push_argument_list(args, loc));
}
/// PRIMARY_EXPR <-
/// IDENTIFIER
/// INTEGER_CONSTANT
/// FLOATING_CONSTANT
/// ( EXPRESSION )
/// BLOCK
fn parse_primary_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let Some(next) = tokens.peek_token() else {
return Err(ErrorInfo {
error: ParseError::ExpectedPrimaryExpression,
loc,
});
};
match next.token() {
Token::IntegerBinConstant
| Token::IntegerHexConstant
| Token::IntegerOctConstant
| Token::IntegerConstant => {
_ = tokens.next();
return Ok(self.parse_integral_constant(&next, next.source_location()));
}
Token::FloatingConstant
| Token::FloatingExpConstant
| Token::DotFloatingConstant
| Token::DotFloatingExpConstant => {
_ = tokens.next();
return Ok(self.parse_floating_constant(&next, next.source_location()));
}
Token::OpenParens => {
let expr =
self.parse_parenthesised(tokens, |this, tokens| this.parse_expr(tokens))?;
return Ok(expr);
}
Token::OpenBrace => {
return self.parse_block(tokens);
}
Token::Ident => {
_ = tokens.next();
let ident = next.lexeme();
let ident = self
.intern
.get_or_insert(intern::Key::String { str: ident });
return Ok(self
.ast
.push_decl_ref_unresolved(self.current_scope(), ident, loc));
}
// TODO: eventually handle paths
_ => {
return Err(ErrorInfo {
error: ParseError::ExpectedPrimaryExpression,
loc,
});
}
}
}
/// POSTFIX_EXPR <-
/// PRIMARY_EXPR
/// PRIMARY_EXPR ( )
/// PRIMARY_EXPR ( ARGUMENT_LIST )
/// PRIMARY_EXPR [ EXPR ]
/// POSTFIX_EXPR . IDENTIFIER
fn parse_postfix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let mut lhs = self.parse_primary_expr(tokens)?;
while let Some(postfix) = self.try_parse_postfix_expr_inner(tokens, lhs)? {
lhs = postfix;
}
Ok(lhs)
}
fn try_parse_postfix_expr_inner(
&mut self,
tokens: &mut TokenIterator,
lhs: Index,
) -> ParseResult<Option<Index>> {
let lhs = if let Some(next) = tokens.peek_token() {
let loc = next.source_location();
match next.token() {
Token::OpenParens => {
let arguments = self.parse_parenthesised(tokens, |this, tokens| {
if tokens.is_next_token(Token::CloseParens) {
Ok(this.ast.push_argument_list([], loc))
} else {
this.parse_argument_list(tokens)
}
})?;
Some(self.ast.push_call_expr(lhs, arguments, loc))
}
Token::OpenSquareBracket => {
let subscript =
self.parse_bracketed(tokens, |this, tokens| this.parse_expr(tokens))?;
Some(
self.ast
.push_binary(Tag::SubscriptExpr, lhs, subscript, loc),
)
}
Token::Dot if tokens.is_next_token2(Token::Ident) => {
_ = tokens.next();
let loc = tokens.current_source_location();
let name = self.parse_ident(tokens)?;
Some(self.ast.push_field_access(lhs, name, loc))
}
_ => None,
}
} else {
None
};
Ok(lhs)
}
fn push_error(&mut self, error: ParseError, loc: SourceLocation) -> Index {
self.errors.push(ErrorInfo { error, loc });
self.ast.push_error(error, loc)
}
/// PREFIX_EXPR <-
/// POSTFIX_EXPR
/// ! POSTFIX_EXPR
/// - POSTFIX_EXPR
/// & POSTFIX_EXPR
/// * POSTFIX_EXPR
fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let next = tokens.peek_token().ok_or(ErrorInfo {
error: ParseError::ExpectedPrefixExpression,
loc: tokens.current_source_location(),
})?;
let loc = next.source_location();
let expr = match next.token() {
Token::Bang => {
_ = tokens.next();
let lhs = self.parse_postfix_expr(tokens)?;
self.ast.push_unary(Tag::Not, lhs, loc)
}
Token::Minus => {
_ = tokens.next();
let lhs = self.parse_postfix_expr(tokens)?;
self.ast.push_unary(Tag::Negate, lhs, loc)
}
Token::Ampersand => {
_ = tokens.next();
let lhs = self.parse_postfix_expr(tokens)?;
self.ast.push_unary(Tag::AddressOf, lhs, loc)
}
Token::Star => {
_ = tokens.next();
let lhs = self.parse_postfix_expr(tokens)?;
self.ast.push_unary(Tag::Deref, lhs, loc)
}
_ => self.parse_postfix_expr(tokens)?,
};
Ok(expr)
}
/// AS_EXPR <-
/// PREFIX_EXPR
/// PREFIX_EXPR as TYPENAME
fn parse_as_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let expr = self.parse_prefix_expr(tokens)?;
if tokens.eat_token(Token::As).is_some() {
let typename = self.parse_type(tokens)?;
return Ok(self.ast.push_cast(expr, typename, loc));
} else {
return Ok(expr);
}
}
/// BINARY_EXPR <-
/// AS_EXPR
/// AS_EXPR * EXPRESSION
/// AS_EXPR / EXPRESSION
/// AS_EXPR % EXPRESSION
/// AS_EXPR + EXPRESSION
/// AS_EXPR - EXPRESSION
/// AS_EXPR << EXPRESSION
/// AS_EXPR >> EXPRESSION
/// AS_EXPR < EXPRESSION
/// AS_EXPR > EXPRESSION
/// AS_EXPR <= EXPRESSION
/// AS_EXPR >= EXPRESSION
/// AS_EXPR == EXPRESSION
/// AS_EXPR != EXPRESSION
/// AS_EXPR & EXPRESSION
/// AS_EXPR ^ EXPRESSION
/// AS_EXPR | EXPRESSION
/// AS_EXPR && EXPRESSION
/// AS_EXPR || EXPRESSION
fn parse_binary_expr(
&mut self,
tokens: &mut TokenIterator,
precedence: u32,
) -> ParseResult<Index> {
let mut node = self.parse_as_expr(tokens)?;
loop {
let Some(tok) = tokens.peek_token() else {
break;
};
let loc = tok.source_location();
let Some(prec) = PRECEDENCE_MAP.get(&tok.token()).cloned() else {
break;
};
if prec < precedence {
break;
}
// SAFETY: we peeked `tok`
let tok = tokens.next().unwrap();
let lhs = node;
let rhs = self.parse_binary_expr(tokens, prec + 1)?;
let tag = match tok.token() {
Token::PipePipe => Tag::Or,
Token::AmpersandAmpersand => Tag::And,
Token::Pipe => Tag::BitOr,
Token::Caret => Tag::BitXOr,
Token::Ampersand => Tag::BitAnd,
Token::BangEqual => Tag::NEq,
Token::EqualEqual => Tag::Eq,
Token::LessEqual => Tag::Le,
Token::GreaterEqual => Tag::Ge,
Token::Less => Tag::Lt,
Token::Greater => Tag::Gt,
Token::GreaterGreater => Tag::Shr,
Token::LessLess => Tag::Shl,
Token::Plus => Tag::Add,
Token::Minus => Tag::Sub,
Token::Percent => Tag::Rem,
Token::Star => Tag::Mul,
Token::Slash => Tag::Div,
_ => unreachable!(),
};
node = self.ast.push_binary(tag, lhs, rhs, loc);
}
Ok(node)
}
/// ASSIGNMENT_EXPR <-
/// BINARY_EXPRESSION
/// BINARY_EXPRESSION ASSIGNMENT_OP EXPRESSION
/// ASSIGNMENT_OP <-
/// = += -= *= /= %= ...
fn parse_assignment_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let lhs = self.parse_binary_expr(tokens, 0)?;
if tokens
.peek_token()
.map(|itm| itm.token().is_assignment_op())
== Some(true)
{
// SAFETY: we peeked
let op = tokens.next().unwrap();
let loc = op.source_location();
let rhs = self.parse_expr(tokens)?;
let rhs = if op.token() == Token::Equal {
rhs
} else {
let tag = match op.token() {
Token::PlusEqual => Tag::Add,
Token::MinusEqual => Tag::Sub,
Token::StarEqual => Tag::Mul,
Token::SlashEqual => Tag::Sub,
Token::PercentEqual => Tag::Rem,
Token::PipeEqual => Tag::BitOr,
Token::CaretEqual => Tag::BitXOr,
Token::AmpersandEqual => Tag::BitAnd,
Token::LessLessEqual => Tag::Shl,
Token::GreaterGreaterEqual => Tag::Shr,
_ => {
unreachable!()
}
};
self.ast.push_binary(tag, lhs, rhs, loc)
};
Ok(self.ast.push_assign(lhs, rhs, loc))
} else {
Ok(lhs)
}
}
/// ELSE_EXPR <-
/// 'else' (IF_EXPR | EXPR_OR_STATEMENT_OR_BLOCK)
fn parse_else_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
// SAFETY: function invariance
let _else_ = tokens.eat_token(Token::Else).unwrap();
if tokens.is_next_token(Token::If) {
self.parse_if_expr(tokens)
} else {
self.parse_expr_or_block_as_block(tokens)
}
}
/// IF_EXPR <-
/// 'if' ( EXPR ) EXPR_OR_STATEMENT_OR_BLOCK ELSE_EXPR?
fn parse_if_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
// SAFETY: function invariance
let iff = tokens.eat_token(Token::If).unwrap();
let loc = iff.source_location();
let cond = self.parse_parenthesised(tokens, |this, tokens| this.parse_expr(tokens))?;
let body = self.parse_expr_or_block_as_block(tokens)?;
if tokens.is_next_token(Token::Else) {
let else_expr = self.parse_else_expr(tokens)?;
Ok(self.ast.push_if_else(cond, body, else_expr, loc))
} else {
Ok(self.ast.push_if(cond, body, loc))
}
}
fn parse_expr_or_block_as_block(
&mut self,
tokens: &mut TokenIterator,
) -> ParseResult<Index> {
let Some(next) = tokens.peek_token() else {
return Err(ErrorInfo {
error: ParseError::ExpectedExpression,
loc: tokens.current_source_location(),
});
};
match next.token() {
Token::OpenBrace => self.parse_block(tokens),
_ => {
let loc = tokens.current_source_location();
let expr = self.parse_expr(tokens)?;
Ok(self.ast.push_block([], Some(expr), loc))
}
}
}
fn parse_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
let loc = tokens.current_source_location();
let Some(next) = tokens.peek_token() else {
return Err(ErrorInfo {
error: ParseError::ExpectedExpression,
loc,
});
};
match next.token() {
Token::If => self.parse_if_expr(tokens),
_ => self.parse_assignment_expr(tokens),
}
}
/// TYPE_DECL <-
/// type IDENTIFIER = TYPE_UNION ;
/// type IDENTIFIER = '(' (TYPE,)* ')' ;
/// type IDENTIFIER = extern? union { (IDENTIFIER: TYPE,)* }
/// type IDENTIFIER = extern? packed? enum { (IDENTIFIER (= EXPRESSION),)* }
/// type IDENTIFIER = extern? packed? struct { (IDENTIFIER: TYPE,)* }
fn parse_type_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
_ = tokens.eat_token(Token::Type).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Type),
loc: tokens.current_source_location(),
});
let name = self.parse_ident(tokens)?;
let loc = tokens.current_source_location();
_ = tokens.eat_token(Token::Equal).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Equal),
loc: tokens.current_source_location(),
});
let (has_attributes, c_like, packed) = {
let vec = tokens.eat_all_zero_or_once(&[Token::Extern, Token::Packed]);
(vec[0] || vec[1], vec[0], vec[1])
};
let Some(next) = tokens.peek_token() else {
return Err(ErrorInfo {
error: ParseError::ExpectedTypeDeclaration,
loc: tokens.current_source_location(),
});
};
let decl = match next.token() {
Token::Struct => self.parse_struct_decl(tokens, name, c_like, packed, loc),
Token::Union => {
unimplemented!()
}
Token::Enum => {
unimplemented!()
}
_ => {
if has_attributes {
return Err(ErrorInfo {
error: ParseError::UnexpectedTypeAttributes,
loc: tokens.current_source_location(),
});
}
match next.token() {
Token::OpenParens => {
// tuple
unimplemented!()
}
Token::Ident => {
// sumtype
unimplemented!()
}
_ => {
return Err(ErrorInfo {
error: ParseError::ExpectedTypeDeclaration,
loc: tokens.current_source_location(),
});
}
}
}
}?;
self.syms
.insert_symbol(self.current_scope(), name, SymbolKind::Type, decl);
Ok(decl)
}
/// SUMTYPE_DECL <-
/// type IDENTIFIER = TYPE_UNION
/// TYPE_UNION <-
/// TYPE (| TYPE_UNION)?
/// IDENTIFIER: TYPE (| TYPE_UNION)?
fn parse_sumtype_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
todo!()
}
/// TUPLE_DECL <-
/// type IDENTIFIER = (TYPE,* )
fn parse_tuple_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
todo!()
}
/// UNION_DECL <-
/// type IDENTIFIER = union { IDENTIFIER: TYPE,* }
fn parse_union_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
todo!()
}
/// ENUM_DECL <-
/// type IDENTIFIER = packed? enum { IDENTIFIER (= EXPRESSION),* }
fn parse_enum_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
todo!()
}
/// STRUCT_DECL <-
/// type IDENTIFIER = extern? packed? struct { STRUCT_FIELD,* }
fn parse_struct_decl(
&mut self,
tokens: &mut TokenIterator,
name: intern::Index,
c_like: bool,
packed: bool,
loc: SourceLocation,
) -> ParseResult<Index> {
// SAFETY: function invariance
_ = tokens.eat_token(Token::Struct).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Struct),
loc: tokens.current_source_location(),
})?;
let decl = self.parse_braced(tokens, |this, tokens| {
this.parse_struct_fields(tokens).map(|fields| {
_ = tokens.eat_token(Token::Comma);
let flags = StructFlags::new(packed, c_like, fields.len() as u32);
this.ast.push_struct_decl(name, flags, fields, loc)
})
})?;
Ok(decl)
}
fn parse_with_trailing_semi<F>(
&mut self,
tokens: &mut TokenIterator,
parse: F,
) -> ParseResult<Index>
where
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<Index>,
{
match parse(self, tokens) {
Ok(i) => {
_ = tokens.eat_token(Token::Semi).ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
Ok(i)
}
Err(err) => {
tokens.advance_past_semi().ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
Ok(self.push_error(err.error, err.loc))
}
}
}
fn parse_inner<F, E>(
&mut self,
tokens: &mut TokenIterator,
open: Token,
close: Token,
parse: F,
on_err: E,
) -> ParseResult<Index>
where
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<Index>,
E: FnOnce(&mut Self, &mut TokenIterator, ErrorInfo, TokenItem) -> ParseResult<Index>,
{
let Some(start) = tokens.eat_token(open) else {
return Err(ErrorInfo {
error: ParseError::ExpectedToken(open),
loc: tokens.current_source_location(),
});
};
match parse(self, tokens) {
Ok(i) => {
_ = tokens.eat_token(close).ok_or(ErrorInfo {
error: match open {
Token::OpenBrace => ParseError::UnmatchedBrace(start.token_pos().start),
Token::OpenParens => {
ParseError::UnmatchedParens(start.token_pos().start)
}
Token::OpenSquareBracket => {
ParseError::UnmatchedSquareBracket(start.token_pos().start)
}
_ => ParseError::UnmatchedDelimiter(start.token_pos().start),
},
loc: tokens.current_source_location(),
})?;
Ok(i)
}
Err(e) => on_err(self, tokens, e, start),
}
}
fn parse_inner2<F>(
&mut self,
tokens: &mut TokenIterator,
open: Token,
close: Token,
parse: F,
) -> ParseResult<Index>
where
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<Index>,
{
self.parse_inner(tokens, open, close, parse, |this, tokens, err, start| {
match close {
Token::CloseBrace => {
tokens.advance_past_end_of_braced().ok_or(ErrorInfo {
error: ParseError::UnmatchedBrace(start.token_pos().start),
loc: tokens.current_source_location(),
})?;
}
Token::CloseParens => {
tokens.advance_past_end_of_parens().ok_or(ErrorInfo {
error: ParseError::UnmatchedParens(start.token_pos().start),
loc: tokens.current_source_location(),
})?;
}
Token::CloseSquareBracket => {
tokens.advance_past_end_of_bracketed().ok_or(ErrorInfo {
error: ParseError::UnmatchedSquareBracket(start.token_pos().start),
loc: tokens.current_source_location(),
})?;
}
Token::Semi => {
tokens.advance_past_semi().ok_or(ErrorInfo {
error: ParseError::ExpectedToken(Token::Semi),
loc: tokens.current_source_location(),
})?;
}
_ => unimplemented!(),
}
Ok(this.push_error(err.error, err.loc))
})
}
fn parse_bracketed<F>(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult<Index>
where
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<Index>,
{
self.parse_inner2(
tokens,
Token::OpenSquareBracket,
Token::CloseSquareBracket,
parse,
)
}
fn parse_braced<F>(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult<Index>
where
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<Index>,
{
self.parse_inner2(tokens, Token::OpenBrace, Token::CloseBrace, parse)
}
fn parse_parenthesised<F>(
&mut self,
tokens: &mut TokenIterator,
parse: F,
) -> ParseResult<Index>
where
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<Index>,
{
self.parse_inner2(tokens, Token::OpenParens, Token::CloseParens, parse)
}
fn parse_struct_fields(
&mut self,
tokens: &mut TokenIterator,
) -> ParseResult<Vec<(intern::Index, Index)>> {
let mut fields = Vec::new();
loop {
fields.push(self.parse_struct_field(tokens)?);
if !tokens.is_next_token(Token::Comma) {
break;
}
if tokens.is_next_token2(Token::CloseBrace) {
break;
}
// skip comma
_ = tokens.next();
}
Ok(fields)
}
/// STRUCT_FIELD <-
/// IDENTIFIER: TYPE
fn parse_struct_field(
&mut self,
tokens: &mut TokenIterator,
) -> ParseResult<(intern::Index, Index)> {
let name = self.parse_ident(tokens)?;
let Some(_) = tokens.eat_token(Token::Colon) else {
return Err(ErrorInfo {
error: ParseError::ExpectedToken(Token::Colon),
loc: tokens.current_source_location(),
});
};
let ty = self.parse_type(tokens)?;
return Ok((name, ty));
}
/// CONSTANT_DECL <-
/// FUNCTION_DECL
/// GLOBAL_DECL
/// STRUCT_DECL
fn parse_constant_decls(
&mut self,
tokens: &mut TokenIterator,
) -> ParseResult<Option<Index>> {
let next = tokens.peek_token().ok_or(ErrorInfo {
error: ParseError::UnexpectedEndOfTokens,
loc: tokens.current_source_location(),
})?;
match next.token() {
Token::Fn => Ok(Some(self.parse_fn_decl(tokens))),
Token::Const => self.parse_const_decl(tokens).map(|i| Some(i)),
Token::Type => self.parse_type_decl(tokens).map(|i| Some(i)),
_ => Ok(None),
}
}
/// FILE <-
/// (FUNCTION_DECL | GLOBAL_DECL)*
fn parse_file(&mut self, tokens: &mut TokenIterator) -> Index {
let start = tokens.current_source_location();
let mut decls = Vec::new();
let file = self.ast.reserve_node();
self.push_scope(file, intern::Index::invalid());
while let Some(next) = tokens.peek_token() {
let loc = next.source_location();
let decl = match self.parse_constant_decls(tokens).and_then(|i| match i {
Some(i) => Ok(i),
None => {
let error = ParseError::UnexpectedTokenAtFileScope;
let node = self.push_error(error, loc);
self.find_next_fn_or_const(tokens);
Ok(node)
}
}) {
Ok(i) => i,
Err(err) => self.push_error(err.error, err.loc),
};
decls.push(decl);
}
self.pop_scope();
self.ast.set_file(file, decls, start);
file
}
/// FILE <-
/// (FUNCTION_DECL | GLOBAL_DECL)*
pub fn parse(&mut self, mut tokens: TokenIterator) {
let file = self.parse_file(&mut tokens);
self.ast.set_root([file]);
eprintln!("resolving decls:");
self.resolve_decl_refs();
eprintln!("interning types:");
self.intern_types();
}
fn push_scope(&mut self, ast: Index, name: intern::Index) {
let parent = self.scopes.last().cloned();
self.scopes.push(ast);
if let Some(parent) = parent {
self.syms.insert_symbol(
ast,
intern::Index::invalid(),
SymbolKind::ParentScope,
parent,
);
}
self.syms.insert_scope(name, ast);
}
fn pop_scope(&mut self) {
self.scopes.pop();
}
fn is_statement(&self, tokens: &mut TokenIterator) -> bool {
let mut tokens = tokens.clone();
let mut braces = 0;
let mut parens = 0;
let mut brackets = 0;
while let Some(itm) = tokens.next() {
match itm.token() {
Token::OpenBrace => {
braces += 1;
}
Token::CloseBrace => {
braces -= 1;
}
Token::OpenParens => {
parens += 1;
}
Token::CloseParens => {
parens -= 1;
}
Token::OpenSquareBracket => {
brackets += 1;
}
Token::CloseSquareBracket => {
brackets -= 1;
}
Token::Semi => {
if braces == 0 && parens == 0 && brackets == 0 {
return true;
}
}
_ => {}
}
if braces < 0 || parens < 0 || brackets < 0 {
break;
}
}
false
}
fn find_next_fn_or_const(&mut self, tokens: &mut TokenIterator) -> Option<()> {
tokens
.advance_until_before_one_of(&[Token::Const, Token::Fn, Token::Type])
.map(|_| ())
}
}
}
pub mod ir_gen {
use intern::InternPool;
use super::*;
use crate::{symbol_table::syms2::Symbols, triples::*};
struct IRGen {
ast: Ast,
syms: Symbols,
intern: InternPool,
ir: IR,
}
impl IRGen {}
}