From 2d8c75ba0d068af6b59f06d9b960d6ab1ee14b07 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 27 Aug 2024 21:52:36 +0200 Subject: [PATCH] comptime folding changes/fixes for declrefs --- src/ast.rs | 26 ++++++ src/comptime.rs | 6 +- src/parser.rs | 212 ++++++++++++++++++++++-------------------------- 3 files changed, 127 insertions(+), 117 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 418c45a..eb37dcb 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -572,6 +572,32 @@ pub mod tree_visitor { pub fn new_range_inclusive(start: Node, end: Node, pre: F1, post: F2) -> Self { Self::new_inner(start, End::Inclusive(end), pre, post) } + pub fn new_seek(tree: &Tree, start: Node, pre: F1, post: F2) -> Self { + let root_frame = Frame { + node: Node::MAX, + children: tree.global_decls.clone(), + }; + Self { + frames: vec![root_frame], + current_node: None, + end: End::Open, + pre, + post, + } + .skip_until(tree, start) + } + pub fn until_before(self, end: Node) -> Self { + Self { + end: End::Exclusive(end), + ..self + } + } + pub fn until_after(self, end: Node) -> Self { + Self { + end: End::Inclusive(end), + ..self + } + } } impl Visitor { diff --git a/src/comptime.rs b/src/comptime.rs index f625ffa..f229ec4 100644 --- a/src/comptime.rs +++ b/src/comptime.rs @@ -2271,7 +2271,11 @@ impl ComptimeNumber { match self { ComptimeNumber::Integral(i) => match i { ComptimeInt::Native { bits, ty } => { - (bits.to_le_bytes().to_vec(), Type::Integer(ty)) + let bytes = (u128::BITS - bits.leading_zeros() + 7) / 8; + ( + bits.to_le_bytes()[..bytes as usize].to_vec(), + Type::Integer(ty), + ) } ComptimeInt::BigInt { bits, ty } => { (bits.to_le_bytes().to_vec(), Type::Integer(ty)) diff --git a/src/parser.rs b/src/parser.rs index 2e34d55..a011706 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1664,7 +1664,7 @@ impl Tree { // simplify tree with compile-time math impl Tree { - fn is_node_comptime(&self, node: Node) -> bool { + fn is_node_comptime(&self, node: Node, check_declrefs: bool) -> bool { match self.nodes.get_node(node) { Tag::Block { statements, @@ -1672,10 +1672,10 @@ impl Tree { } => statements .iter() .chain(trailing_expr.into_iter()) - .all(|n| self.is_node_comptime(*n)), + .all(|n| self.is_node_comptime(*n, true)), Tag::Constant { .. } => true, Tag::ExplicitCast { lhs, typename } => { - self.is_node_comptime(*lhs) + self.is_node_comptime(*lhs, true) && match self.type_of_node(*typename) { Type::Bool | Type::ComptimeNumber @@ -1684,9 +1684,34 @@ impl Tree { _ => false, } } - Tag::DeclRef(lhs) | Tag::Not { lhs } | Tag::Negate { lhs } => { - self.is_node_comptime(*lhs) + &Tag::DeclRef(lhs) if check_declrefs => { + let start = lhs; + let end = node; + let mut is_comptime = true; + + ast::tree_visitor::Visitor::new_seek( + self,start, + |_: &Tree, _| { + }, + |tree: &Tree, node| match tree.nodes.get_node(node) { + &Tag::Assign { lhs, rhs } => { + if lhs == start || matches!(tree.nodes.get_node(lhs), &Tag::DeclRef(decl) if decl == start) { + is_comptime &= self.is_node_comptime(rhs, true); + } + } + &Tag::Ref { lhs } if lhs == start => { + // recursively checking for derefs would get very complicated. + is_comptime = false; + } + _ => {} + }, + ) + .until_after(end) + .visit(self); + + is_comptime } + Tag::Not { lhs } | Tag::Negate { lhs } => self.is_node_comptime(*lhs, true), Tag::Or { lhs, rhs } | Tag::And { lhs, rhs } | Tag::BitOr { lhs, rhs } @@ -1704,72 +1729,19 @@ impl Tree { | Tag::Sub { lhs, rhs } | Tag::Mul { lhs, rhs } | Tag::Rem { lhs, rhs } - | Tag::Div { lhs, rhs } => self.is_node_comptime(*lhs) && self.is_node_comptime(*rhs), + | Tag::Div { lhs, rhs } => { + self.is_node_comptime(*lhs, true) && self.is_node_comptime(*rhs, true) + } _ => false, } } - fn try_fold_comptime_inner(&mut self, node: Node) { - if self.is_node_comptime(node) { - _ = self.fold_comptime_inner(node); - } - } - fn fold_comptime_with_visitor(&mut self, decl: Node) { ast::tree_visitor::Visitor::new( decl, |_: &mut Tree, _| {}, |tree: &mut Tree, node| { - - let value_node = if let &Tag::DeclRef(lhs) = tree.nodes.get_node(node) { - let start = lhs; - let end = node; - let mut is_comptime = true; - let mut last_value = None; - eprintln!( - "checking if %{}, referencing %{} is comptime-evaluable", - node.get(), - lhs.get() - ); - ast::tree_visitor::Visitor::new_range_inclusive( - decl, - end, - |_: &Tree, _| { - }, - |tree: &Tree, node| match tree.nodes.get_node(node) { - &Tag::Assign { lhs, rhs } => { - if lhs == start || matches!(tree.nodes.get_node(lhs), &Tag::DeclRef(decl) if decl == start) { - eprintln!("found assignment at %{}", node.get()); - is_comptime &= tree.is_node_comptime(rhs); - if is_comptime { - last_value = Some(rhs); - } - } - } - &Tag::Ref { lhs } if lhs == start => { - // recursively checking for derefs would get very complicated. - is_comptime = false; - } - _ => {} - }, - ) - .skip_until(tree, start) - .visit(tree); - - eprintln!( - "%{} is {}comptime-evaluable.", - node.get(), - if is_comptime { "" } else { "not " } - ); - - eprintln!("%{node} comptime-value is %{last_value:?}"); - - is_comptime.then_some(last_value).flatten().unwrap_or(node) - }else { - node - }; - - if let Ok(value) = tree.fold_comptime_inner(value_node) { + if let Ok(value) = tree.fold_comptime_inner(node, false) { let (bytes, ty) = value.into_bytes_and_type(); let idx = tree.strings.insert(bytes); @@ -1783,8 +1755,12 @@ impl Tree { .visit_mut(self); } - fn fold_comptime_inner(&mut self, decl: Node) -> comptime::Result { - if self.is_node_comptime(decl) { + fn fold_comptime_inner( + &mut self, + decl: Node, + check_declrefs: bool, + ) -> comptime::Result { + if self.is_node_comptime(decl, check_declrefs) { match self.nodes.get_node(decl) { Tag::Constant { bytes, ty } => { let bytes = match bytes { @@ -1823,12 +1799,12 @@ impl Tree { return Ok(number); } Tag::Negate { lhs } => { - let lhs = self.fold_comptime_inner(*lhs)?; + let lhs = self.fold_comptime_inner(*lhs, true)?; return Ok(lhs.neg()?); } Tag::ExplicitCast { lhs, typename } => { let ty = self.type_of_node(*typename); - let lhs = self.fold_comptime_inner(*lhs)?; + let lhs = self.fold_comptime_inner(*lhs, true)?; return match ty { Type::Bool => lhs.into_bool(), @@ -1838,156 +1814,160 @@ impl Tree { }; } Tag::Not { lhs } => { - let lhs = self.fold_comptime_inner(*lhs)?; + let lhs = self.fold_comptime_inner(*lhs, true)?; return lhs.not(); } Tag::Or { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.or(rhs); } Tag::And { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.and(rhs); } Tag::Eq { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.eq(rhs); } Tag::NEq { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.eq(rhs)?.not(); } Tag::Lt { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.lt(rhs); } Tag::Gt { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.gt(rhs); } Tag::Le { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.le(rhs); } Tag::Ge { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.ge(rhs); } Tag::BitOr { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.bitor(rhs); } Tag::BitAnd { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.bitand(rhs); } Tag::BitXOr { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.bitxor(rhs); } Tag::Shl { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.shl(rhs); } Tag::Shr { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.shr(rhs); } Tag::Add { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.add(rhs); } Tag::Sub { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.sub(rhs); } Tag::Mul { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.mul(rhs); } Tag::Rem { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.rem(rhs); } Tag::Div { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); - let lhs = self.fold_comptime_inner(lhs)?; - let rhs = self.fold_comptime_inner(rhs)?; + let lhs = self.fold_comptime_inner(lhs, true)?; + let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.div(rhs); } &Tag::DeclRef(lhs) => { - variant!(self.nodes.get_node(lhs) => &Tag::VarDecl { assignment, .. }); - - let start = assignment.unwrap_or(lhs); + let start = lhs; let end = decl; let mut last_value = None; - ast::tree_visitor::Visitor::new_range( - start, - end, - |_: &Tree, _| {}, + + ast::tree_visitor::Visitor::new_seek( + self,start, + |_: &Tree, node| { + }, |tree: &Tree, node| match tree.nodes.get_node(node) { - &Tag::Assign { lhs, rhs } if lhs == start => { + &Tag::Assign { lhs, rhs } => { + if lhs == start || matches!(tree.nodes.get_node(lhs), &Tag::DeclRef(decl) if decl == start) { last_value = Some(rhs); + } } _ => {} }, ) - .visit(self); + .until_after(end) + .visit(self); - return self - .fold_comptime_inner(last_value.ok_or(comptime::Error::NotComptime)?); + return self.fold_comptime_inner( + last_value.ok_or(comptime::Error::NotComptime)?, + true, + ); } _ => { unreachable!() @@ -2002,10 +1982,10 @@ impl Tree { for decl in self.global_decls.clone() { match self.nodes.get_node(decl) { Tag::FunctionDecl { body, .. } => { - _ = self.fold_comptime_inner(*body); + self.fold_comptime_with_visitor(*body); } Tag::GlobalDecl { assignment, .. } => { - _ = self.fold_comptime_inner(*assignment); + self.fold_comptime_with_visitor(*assignment); } _ => unreachable!(), }