comptime folding,

- reduced scope of foldability to just simple expressions and declrefs to globaldecls
This commit is contained in:
Janis 2024-09-16 16:55:04 +02:00
parent 3d014ad985
commit 4f70fa2246

View file

@ -9,7 +9,10 @@ use std::{
use intern::{InternPool, PointerFlags, StructFlags}; use intern::{InternPool, PointerFlags, StructFlags};
use num_bigint::BigInt; use num_bigint::BigInt;
use crate::{lexer::SourceLocation, tokens::Token, writeln_indented}; use crate::{
ast::FloatingType, comptime::ComptimeNumber, lexer::SourceLocation, tokens::Token,
writeln_indented,
};
pub mod intern { pub mod intern {
use std::{ use std::{
@ -21,6 +24,7 @@ pub mod intern {
use num_bigint::{BigInt, BigUint, Sign}; use num_bigint::{BigInt, BigUint, Sign};
use crate::{ use crate::{
ast::IntegralType,
common::{from_lo_hi_dwords, into_lo_hi_dwords}, common::{from_lo_hi_dwords, into_lo_hi_dwords},
variant, variant,
}; };
@ -533,7 +537,73 @@ pub mod intern {
} }
} }
} }
pub fn from_ast1_type(&self, pointer_bits: u16, ty: &crate::ast::Type) -> Index {
match ty {
crate::ast::Type::Bool => self.get_bool_type(),
crate::ast::Type::ComptimeNumber => self.get_comptime_int_type(),
crate::ast::Type::Integer(i) => self.get_assume_present(&{
if i.signed {
Key::SIntType { bits: i.bits }
} else {
Key::UIntType { bits: i.bits }
} }
}),
crate::ast::Type::Floating(crate::ast::FloatingType::Binary32) => {
self.get_f32_type()
}
crate::ast::Type::Floating(crate::ast::FloatingType::Binary64) => {
self.get_f64_type()
}
crate::ast::Type::Pointer { constness, pointee } => {
self.get_assume_present(&Key::PointerType {
pointee: self.from_ast1_type(pointer_bits, &pointee),
flags: PointerFlags::new(*constness, false, false),
})
}
crate::ast::Type::Fn { .. } => {
unimplemented!()
}
_ => {
todo!()
}
}
}
pub fn as_ast1_type(&self, pointer_bits: u16, index: Index) -> crate::ast::Type {
use crate::ast::Type;
match self.get_key(index) {
Key::UIntType { bits } => Type::Integer(IntegralType::new(false, bits)),
Key::SIntType { bits } => Type::Integer(IntegralType::new(true, bits)),
Key::SimpleType { ty } => match ty {
SimpleType::F32 => Type::Floating(crate::ast::FloatingType::Binary32),
SimpleType::F64 => Type::Floating(crate::ast::FloatingType::Binary64),
SimpleType::Bool => Type::Bool,
SimpleType::Void => Type::Void,
SimpleType::USize => Type::Integer(IntegralType::new(false, pointer_bits)),
SimpleType::ISize => Type::Integer(IntegralType::new(true, pointer_bits)),
SimpleType::ComptimeInt => Type::comptime_number(),
},
Key::PointerType { pointee, flags } => Type::Pointer {
constness: flags.is_const,
pointee: Box::new(self.as_ast1_type(pointer_bits, pointee)),
},
Key::FunctionType {
return_type,
parameters,
} => Type::Fn {
parameter_types: parameters
.into_iter()
.map(|i| self.as_ast1_type(pointer_bits, i))
.collect(),
return_type: Box::new(self.as_ast1_type(pointer_bits, return_type)),
},
_ => unimplemented!(),
}
}
}
pub const AMD64_POINTER_BITS: u16 = 64;
impl InternPool { impl InternPool {
pub fn create() -> Self { pub fn create() -> Self {
@ -617,6 +687,7 @@ pub mod intern {
_ = self.extend_words(words); _ = self.extend_words(words);
self.create_item(Tag::NegativeInt, i) self.create_item(Tag::NegativeInt, i)
} }
Key::UIntType { bits } => self.create_item(Tag::UIntType, bits as u32), Key::UIntType { bits } => self.create_item(Tag::UIntType, bits as u32),
Key::SIntType { bits } => self.create_item(Tag::SIntType, 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::SimpleType { ty } => self.create_item(Tag::SimpleType, ty as u8 as u32),
@ -1122,6 +1193,55 @@ enum Tag {
Undefined, Undefined,
} }
impl Tag {
fn is_type(&self) -> bool {
match self {
Tag::TypeDeclRef
| Tag::TypeDeclRefUnresolved
| Tag::PointerType
| Tag::InternedType
| Tag::ArrayType
| Tag::StructDecl => true,
_ => false,
}
}
fn is_expr(&self) -> bool {
match self {
Tag::Constant
| Tag::DeclRef
| Tag::Deref
| Tag::CallExpr
| Tag::AddressOf
| 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::Rem
| Tag::SubscriptExpr
| Tag::IfExpr
| Tag::IfElseExpr
| Tag::Block
| &Tag::BlockTrailingExpr => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)] #[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)]
enum ParseError { enum ParseError {
#[error("Unexpected end of token iter.")] #[error("Unexpected end of token iter.")]
@ -2134,7 +2254,7 @@ impl Ast {
Tag::FieldDecl => self.get_type_of_node(ip, cache, data.as_index_intern().0), Tag::FieldDecl => self.get_type_of_node(ip, cache, data.as_index_intern().0),
Tag::InternedType => data.as_intern(), Tag::InternedType => data.as_intern(),
Tag::TypeDeclRef | Tag::TypeDeclRefUnresolved | Tag::PointerType | Tag::ArrayType => { Tag::TypeDeclRef | Tag::TypeDeclRefUnresolved | Tag::PointerType | Tag::ArrayType => {
unreachable!() ip.get_void_type()
} }
}; };
@ -2289,25 +2409,24 @@ impl Ast {
let is_comptime = match tag { let is_comptime = match tag {
Tag::Parameter => false, Tag::Parameter => false,
Tag::Block | Tag::BlockTrailingExpr => are_children_comptime(self, cache), // Tag::Block | Tag::BlockTrailingExpr => are_children_comptime(self, cache),
Tag::Constant => true, Tag::Constant => true,
Tag::ReturnStmt => true, Tag::ReturnStmt => true,
Tag::ReturnExprStmt => are_children_comptime(self, cache), Tag::ReturnExprStmt => are_children_comptime(self, cache),
Tag::VarDecl | Tag::MutVarDecl => true, Tag::MutVarDecl | Tag::MutVarDeclAssignment => false,
Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => { // Tag::VarDecl => true,
are_children_comptime(self, cache) Tag::VarDeclAssignment => are_children_comptime(self, cache),
}
Tag::GlobalDecl => true, Tag::GlobalDecl => true,
Tag::StructDecl => true, Tag::StructDecl => true,
Tag::FieldDecl => true, Tag::FieldDecl => true,
Tag::DeclRef => self.tags[data.as_index().index()] == Tag::GlobalDecl, Tag::DeclRef => self.tags[data.as_index().index()] == Tag::GlobalDecl,
Tag::InternedType | Tag::PointerType | Tag::ArrayType | Tag::TypeDeclRef => true, Tag::InternedType | Tag::PointerType | Tag::ArrayType | Tag::TypeDeclRef => true,
Tag::CallExpr => false, // are_children_comptime(self, cache), // Tag::CallExpr => are_children_comptime(self, cache),
Tag::FieldAccess => { // Tag::FieldAccess => {
let parent = data.as_index_intern().0; // let parent = data.as_index_intern().0;
cache.mark_as_dominated_by(index, parent); // cache.mark_as_dominated_by(index, parent);
self.is_node_comptime_evaluable(cache, parent) // self.is_node_comptime_evaluable(cache, parent)
} // }
Tag::ArgumentList => are_children_comptime(self, cache), Tag::ArgumentList => are_children_comptime(self, cache),
Tag::Argument => self.is_node_comptime_evaluable(cache, data.as_index()), Tag::Argument => self.is_node_comptime_evaluable(cache, data.as_index()),
Tag::NamedArgument => { Tag::NamedArgument => {
@ -2343,7 +2462,7 @@ impl Ast {
cache.mark_as_dominated_by(index, left); cache.mark_as_dominated_by(index, left);
are_children_comptime(self, cache) are_children_comptime(self, cache)
} }
Tag::IfExpr | Tag::IfElseExpr => are_children_comptime(self, cache), // Tag::IfExpr | Tag::IfElseExpr => are_children_comptime(self, cache),
Tag::Root Tag::Root
| Tag::File | Tag::File
| Tag::FunctionProto | Tag::FunctionProto
@ -2354,6 +2473,7 @@ impl Ast {
| Tag::TypeDeclRefUnresolved | Tag::TypeDeclRefUnresolved
| Tag::Error | Tag::Error
| Tag::Undefined => false, | Tag::Undefined => false,
_ => false,
}; };
cache.insert(index, is_comptime); cache.insert(index, is_comptime);
@ -2362,95 +2482,283 @@ impl Ast {
} }
} }
// fn comptime_value_of_node( fn comptime_value_of_node(
// &self, &self,
// ip: &InternPool, ip: &InternPool,
// pointer_bits: u16, pointer_bits: u16,
// cache: &mut TypeCache, cache: &mut TypeCache,
// index: Index, index: Index,
// ) -> crate::comptime::ComptimeNumber { ) -> Option<crate::comptime::ComptimeNumber> {
// let tag = self.tags[index.index()]; let tag = self.tags[index.index()];
// let data = self.datas[index.index()]; let data = self.datas[index.index()];
// match tag { match tag {
// Tag::Root => todo!(), Tag::Constant => {
// Tag::File => todo!(), let (ty, value) = data.as_index_intern();
// Tag::FunctionProto => todo!(), let ty = self.get_type_of_node(ip, cache, ty);
// Tag::FunctionDecl => todo!(), Some(interned_type_and_value_to_comptime_number(
// Tag::ParameterList => todo!(), ip,
// Tag::Parameter => todo!(), pointer_bits,
// Tag::Block => todo!(), ty,
// Tag::BlockTrailingExpr => { value,
// let (a, b) = data.as_extra_range(); ))
// if a != b { }
// self.comptime_value_of_node( Tag::GlobalDecl => {
// ip, let (_, offset) = data.as_intern_and_extra_offset();
// pointer_bits, self.comptime_value_of_node(
// cache, ip,
// Index::new(self.extra[b - 1]), pointer_bits,
// ) cache,
// } else { Index::new(self.extra[offset + 1]),
// None )
// } }
// } Tag::VarDeclAssignment => {
// Tag::Constant => { let (a, _) = data.as_extra_range();
// let (ty, value) = data.as_index_intern(); self.comptime_value_of_node(ip, pointer_bits, cache, Index::new(self.extra[a + 1]))
// let ty = self.get_type_of_node(ip, cache, ty); }
// interned_type_and_value_to_comptime_number(ip, pointer_bits, ty, value) Tag::DeclRef => self.comptime_value_of_node(ip, pointer_bits, cache, data.as_index()),
// } Tag::ExplicitCast => {
// Tag::ExprStmt => todo!(), let (expr, ty) = data.as_two_indices();
// Tag::ReturnStmt => todo!(), let ty = ip.as_ast1_type(
// Tag::ReturnExprStmt => todo!(), intern::AMD64_POINTER_BITS,
// Tag::VarDecl => todo!(), self.datas[ty.index()].as_intern(),
// Tag::MutVarDecl => todo!(), );
// Tag::VarDeclAssignment => todo!(), let val = self.comptime_value_of_node(ip, pointer_bits, cache, expr);
// Tag::MutVarDeclAssignment => todo!(), val.and_then(|i| i.explicit_cast(ty).ok())
// Tag::GlobalDecl => todo!(), }
// Tag::StructDecl => todo!(), Tag::Add => {
// Tag::FieldDecl => todo!(), let (a, b) = data.as_two_indices();
// Tag::DeclRef => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, a)
// Tag::DeclRefUnresolved => todo!(), .and_then(|a| {
// Tag::InternedType => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, b)
// Tag::TypeDeclRef => todo!(), .and_then(|b| a.add(b).ok())
// Tag::TypeDeclRefUnresolved => todo!(), })
// Tag::PointerType => todo!(), }
// Tag::ArrayType => todo!(), Tag::Sub => {
// Tag::CallExpr => todo!(), let (a, b) = data.as_two_indices();
// Tag::FieldAccess => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, a)
// Tag::ArgumentList => todo!(), .and_then(|a| {
// Tag::Argument => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, b)
// Tag::NamedArgument => todo!(), .and_then(|b| a.sub(b).ok())
// Tag::ExplicitCast => todo!(), })
// Tag::Deref => todo!(), }
// Tag::AddressOf => todo!(), Tag::Mul => {
// Tag::Not => todo!(), let (a, b) = data.as_two_indices();
// Tag::Negate => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, a)
// Tag::Or => todo!(), .and_then(|a| {
// Tag::And => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, b)
// Tag::BitOr => todo!(), .and_then(|b| a.mul(b).ok())
// Tag::BitXOr => todo!(), })
// Tag::BitAnd => todo!(), }
// Tag::Eq => todo!(), Tag::Div => {
// Tag::NEq => todo!(), let (a, b) = data.as_two_indices();
// Tag::Lt => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, a)
// Tag::Gt => todo!(), .and_then(|a| {
// Tag::Le => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, b)
// Tag::Ge => todo!(), .and_then(|b| a.div(b).ok())
// Tag::Shl => todo!(), })
// Tag::Shr => todo!(), }
// Tag::Add => todo!(), Tag::Rem => {
// Tag::Sub => todo!(), let (a, b) = data.as_two_indices();
// Tag::Mul => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, a)
// Tag::Div => todo!(), .and_then(|a| {
// Tag::Rem => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, b)
// Tag::Assign => todo!(), .and_then(|b| a.rem(b).ok())
// Tag::SubscriptExpr => todo!(), })
// Tag::IfExpr => todo!(), }
// Tag::IfElseExpr => todo!(), Tag::Shl => {
// Tag::Error => todo!(), let (a, b) = data.as_two_indices();
// Tag::Undefined => todo!(), self.comptime_value_of_node(ip, pointer_bits, cache, a)
// } .and_then(|a| {
// } self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.shl(b).ok())
})
}
Tag::Shr => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.shr(b).ok())
})
}
Tag::BitAnd => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.bitand(b).ok())
})
}
Tag::BitOr => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.bitor(b).ok())
})
}
Tag::BitXOr => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.bitxor(b).ok())
})
}
Tag::And => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.and(b).ok())
})
}
Tag::Or => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.or(b).ok())
})
}
Tag::Eq => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.eq(b).ok())
})
}
Tag::NEq => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.eq(b).and_then(|i| i.not()).ok())
})
}
Tag::Gt => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.gt(b).ok())
})
}
Tag::Lt => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.lt(b).ok())
})
}
Tag::Le => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.le(b).ok())
})
}
Tag::Ge => {
let (a, b) = data.as_two_indices();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| {
self.comptime_value_of_node(ip, pointer_bits, cache, b)
.and_then(|b| a.ge(b).ok())
})
}
Tag::Not => {
let a = data.as_index();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| a.not().ok())
}
Tag::Negate => {
let a = data.as_index();
self.comptime_value_of_node(ip, pointer_bits, cache, a)
.and_then(|a| a.neg().ok())
}
_ => None,
}
}
}
fn comptime_number_to_interned_type_and_value(
ip: &mut InternPool,
pointer_bits: u16,
comptime: ComptimeNumber,
) -> (intern::Index, intern::Index) {
use crate::ast::IntegralType;
let (value, ty) = comptime.into_bytes_and_type();
let value = match ty {
crate::ast::Type::Bool => {
if value.get(0) != Some(&1) {
ip.get_false_value()
} else {
ip.get_true_value()
}
}
crate::ast::Type::Integer(IntegralType { bits: 65.., .. })
| crate::ast::Type::ComptimeNumber => {
let bigint = BigInt::from_signed_bytes_le(&value);
if bigint.sign() == num_bigint::Sign::Minus {
ip.get_or_insert(intern::Key::NegativeInt { bigint })
} else {
ip.get_or_insert(intern::Key::PositiveInt { bigint })
}
}
crate::ast::Type::Integer(i) => match i.bits {
..=32 => {
let mut buf = [0u8; 4];
buf[..value.len()].copy_from_slice(&value[..]);
if i.signed {
ip.get_or_insert(intern::Key::SIntSmall {
bits: i32::from_le_bytes(buf),
})
} else {
ip.get_or_insert(intern::Key::UIntSmall {
bits: u32::from_le_bytes(buf),
})
}
}
..=64 => {
let mut buf = [0u8; 8];
buf[..value.len()].copy_from_slice(&value[..]);
if i.signed {
ip.get_or_insert(intern::Key::SInt64 {
bits: i64::from_le_bytes(buf),
})
} else {
ip.get_or_insert(intern::Key::UInt64 {
bits: u64::from_le_bytes(buf),
})
}
}
_ => unreachable!(),
},
crate::ast::Type::Floating(FloatingType::Binary32) => {
let mut buf = [0u8; 4];
buf[..value.len()].copy_from_slice(&value[..]);
ip.get_or_insert(intern::Key::F32 {
bits: f32::from_le_bytes(buf),
})
}
crate::ast::Type::Floating(FloatingType::Binary64) => {
let mut buf = [0u8; 8];
buf[..value.len()].copy_from_slice(&value[..]);
ip.get_or_insert(intern::Key::F64 {
bits: f64::from_le_bytes(buf),
})
}
_ => unimplemented!(),
};
let ty = ip.from_ast1_type(pointer_bits, &ty);
(value, ty)
} }
fn interned_type_and_value_to_comptime_number( fn interned_type_and_value_to_comptime_number(
@ -2595,11 +2903,39 @@ pub struct AstRenderer<'a> {
#[allow(dead_code)] #[allow(dead_code)]
syms: &'a crate::symbol_table::syms2::Symbols, syms: &'a crate::symbol_table::syms2::Symbols,
ip: &'a InternPool, ip: &'a InternPool,
scopes: Vec<Index>,
cache: TypeCache, cache: TypeCache,
comptime_cache: ComptimeCache, comptime_cache: ComptimeCache,
} }
pub struct NodeDisplay<'a> {
node: Index,
ast: &'a Ast,
ip: &'a InternPool,
}
impl<'a> Display for NodeDisplay<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let node = self.node;
let tag = self.ast.tags[node.index()];
let loc = self.ast.source_locs[node.index()];
let children = Children(self.ast.get_node_children(node));
let ty = self
.ast
.get_type_of_node(self.ip, &mut TypeCache::new(), node);
let is_comptime = self
.ast
.is_node_comptime_evaluable(&mut ComptimeCache::default(), node);
writeln!(
f,
"{node} {}({ty}) = ({loc}) {tag:?} {children}",
if is_comptime { "CONST " } else { "" }
)?;
Ok(())
}
}
impl<'a> AstRenderer<'a> { impl<'a> AstRenderer<'a> {
pub fn new( pub fn new(
ast: &'a Ast, ast: &'a Ast,
@ -2610,7 +2946,6 @@ impl<'a> AstRenderer<'a> {
ast, ast,
syms, syms,
ip, ip,
scopes: Vec::new(),
cache: TypeCache::new(), cache: TypeCache::new(),
comptime_cache: ComptimeCache::default(), comptime_cache: ComptimeCache::default(),
} }
@ -2624,12 +2959,6 @@ impl<'a> AstRenderer<'a> {
) -> core::fmt::Result { ) -> core::fmt::Result {
let tag = self.ast.tags[node.index()]; let tag = self.ast.tags[node.index()];
let loc = self.ast.source_locs[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 children = Children(self.ast.get_node_children(node));
let ty = self.ast.get_type_of_node(self.ip, &mut self.cache, node); let ty = self.ast.get_type_of_node(self.ip, &mut self.cache, node);
@ -2647,13 +2976,6 @@ impl<'a> AstRenderer<'a> {
self.render_node(w, indent + 1, child)?; self.render_node(w, indent + 1, child)?;
} }
match tag {
Tag::File | Tag::FunctionDecl | Tag::Block | Tag::BlockTrailingExpr => {
self.scopes.pop();
}
_ => {}
}
Ok(()) Ok(())
} }
fn render<W: core::fmt::Write>(&mut self, w: &mut W) -> core::fmt::Result { fn render<W: core::fmt::Write>(&mut self, w: &mut W) -> core::fmt::Result {
@ -2720,16 +3042,16 @@ pub mod ast_gen {
AstRenderer::new(&self.ast, &self.intern, &self.syms) AstRenderer::new(&self.ast, &self.intern, &self.syms)
} }
pub fn fold_and_typecheck(&mut self) { pub fn node_display(&self, node: Index) -> NodeDisplay<'_> {
enum Asdf { NodeDisplay {
Pre(Index), node,
Post(Index), ast: &self.ast,
ip: &self.intern,
} }
let mut nodes = self.ast.get_root_file_indices().collect::<Vec<_>>();
let mut cache = TypeCache::new();
} }
pub fn create_comptime_folding_graph(&mut self) { pub fn create_comptime_folding_graph(&mut self, pointer_bits: u16) {
let mut type_cache = TypeCache::new();
let mut cache = ComptimeCache::default(); let mut cache = ComptimeCache::default();
let mut nodes = self.ast.get_root_file_indices().collect::<Vec<_>>(); let mut nodes = self.ast.get_root_file_indices().collect::<Vec<_>>();
while let Some(node) = nodes.pop() { while let Some(node) = nodes.pop() {
@ -2738,14 +3060,14 @@ pub mod ast_gen {
} }
} }
let mut node_map = Vec::<u32>::new(); let mut node_map = Vec::<Index>::new();
let edges = cache let edges = cache
.inner .inner
.iter() .iter()
.filter(|(_, b)| **b) .filter(|(_, b)| **b)
.map(|(e, _)| self.ast.get_node_children(*e).into_iter().map(|d| (*e, d))) .map(|(e, _)| self.ast.get_node_children(*e).into_iter().map(|d| (*e, d)))
.flatten() .flatten()
.map(|(a, b)| (a.into_u32(), b.into_u32())) // .map(|(a, b)| (a.into_u32(), b.into_u32()))
.map(|(a, b)| { .map(|(a, b)| {
( (
node_map.iter().position(|&i| i == a).unwrap_or_else(|| { node_map.iter().position(|&i| i == a).unwrap_or_else(|| {
@ -2760,21 +3082,63 @@ pub mod ast_gen {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let extra_nodes = cache
.inner
.iter()
.filter(|(i, b)| **b)
.filter_map(|(i, _)| (!node_map.contains(i)).then(|| node_map.push(*i)))
.count();
eprintln!("cache: {cache:?}"); eprintln!("cache: {cache:?}");
eprintln!("node_map: {node_map:?}");
eprintln!("edges: {edges:?}"); eprintln!("edges: {edges:?}");
let mut graph = petgraph::stable_graph::StableDiGraph::<(), ()>::from_edges(edges); let mut graph = petgraph::stable_graph::StableDiGraph::<(), ()>::from_edges(edges);
for _ in 0..extra_nodes {
graph.add_node(());
}
std::fs::write( std::fs::write(
"comptime_graph.dot", "comptime_graph.dot",
&format!("{:?}", petgraph::dot::Dot::new(&graph)), &format!(
"{:?}",
petgraph::dot::Dot::with_attr_getters(
&graph,
&[],
&|graph, edgeref| { "".to_string() },
&|graph, noderef| {
format!("label = \"{}\"", node_map[noderef.0.index()])
}
)
),
) )
.expect("writing comptime graph repr"); .expect("writing comptime graph repr");
let a = graph
.externals(petgraph::Direction::Outgoing)
.collect::<Vec<_>>();
while let Some(external) = graph.externals(petgraph::Direction::Outgoing).next() { while let Some(external) = graph.externals(petgraph::Direction::Outgoing).next() {
_ = node_map[external.index()]; let node = node_map[external.index()];
if !(self.ast.tags[node.index()] == Tag::Constant
|| self.ast.tags[node.index()].is_type())
&& self.ast.tags[node.index()].is_expr()
{
eprintln!("folding {node}:\n{}", self.node_display(node));
let value = self
.ast
.comptime_value_of_node(&self.intern, pointer_bits, &mut type_cache, node)
.expect(&format!("{node} has value of None?"));
let (value, ty) = comptime_number_to_interned_type_and_value(
&mut self.intern,
pointer_bits,
value,
);
let ty = self.ast.push_interend_type(ty, self.ast.get_loc(node));
self.ast.set_tag_data_source_loc(
node,
Tag::Constant,
Data::index_and_intern(ty, value),
self.ast.get_loc(node),
);
} else {
eprintln!("rejecting {node}:\n{}", self.node_display(node));
}
// comptime fold node // comptime fold node
graph.remove_node(external); graph.remove_node(external);
} }
@ -4345,7 +4709,7 @@ pub mod ast_gen {
self.ast.set_root([file]); self.ast.set_root([file]);
eprintln!("resolving decls:"); eprintln!("resolving decls:");
self.resolve_decl_refs(); self.resolve_decl_refs();
self.create_comptime_folding_graph(); self.create_comptime_folding_graph(intern::AMD64_POINTER_BITS);
eprintln!("interning types:"); eprintln!("interning types:");
self.intern_types(); self.intern_types();
} }