pulled out modules into separate files

This commit is contained in:
Janis 2025-03-06 02:28:02 +01:00
parent 6cc1822ec6
commit f30b7827b8
5 changed files with 3389 additions and 3577 deletions

842
src/ast2/ir.rs Normal file
View file

@ -0,0 +1,842 @@
use std::collections::HashMap;
use crate::{
ast2::{
intern::{self, AMD64_POINTER_TYPE_INFO},
Index,
},
triples::{self, Inst, IR},
};
#[derive(Debug, thiserror::Error)]
enum Error {
#[error("This visitor does not implement visiting this tag.")]
Unimplemented,
}
use super::{
intern::InternPoolWrapper as InternPool,
visitor::{AstExt, AstVisitorTrait},
TypeCache,
};
struct IrBuilder {
functions: Vec<Function>,
}
struct Function {
ir: IR,
}
struct IrFunctionBuilder<'a> {
ir: &'a mut IR,
type_cache: &'a mut TypeCache,
ref_lookup: &'a mut HashMap<Index, u32>,
ip: &'a InternPool,
function: Function,
}
impl<'a> AstVisitorTrait for IrFunctionBuilder<'a> {
type Error = Error;
type Value = Option<u32>;
const UNIMPL: Self::Error = Error::Unimplemented;
fn visit_block(
&mut self,
ast: &mut super::Ast,
idx: super::Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Block);
let (a, b) = data.as_extra_range();
ast.extra[a..b]
.to_vec()
.into_iter()
.map(|i| Index::from_u32(i).unwrap())
.map(|i| self.visit_any(ast, i))
.try_fold((), |_, e| e.map(crate::unit))?;
Ok(None)
}
fn visit_place_to_value_conversion(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::PlaceToValueConversion);
let expr = data.as_index();
// idx's (this) type is the pointee type
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
let expr = self.visit_any(ast, expr)?.unwrap();
let ir = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr)));
Ok(Some(ir))
}
fn visit_value_to_place_conversion(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::ValueToPlaceConversion);
let expr = data.as_index();
// expr's type is the pointee type
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
let expr = self.visit_any(ast, expr)?.unwrap();
let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO);
let alloca = self.ir.push(
Inst::Alloca,
Some(triples::Data::new(info.size(), info.align())),
);
_ = self
.ir
.push(Inst::Store(ty), Some(triples::Data::new(expr, alloca)));
Ok(Some(alloca))
}
fn visit_decl_ref(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::DeclRef);
let decl = data.as_index();
let alloca = self.ref_lookup.get(&decl).cloned().expect("declref");
Ok(Some(alloca))
}
fn visit_var_decl(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_var_decl_common(ast, idx)
}
fn visit_mut_var_decl(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_var_decl_common(ast, idx)
}
fn visit_var_assign_decl(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_var_decl_common(ast, idx)
}
fn visit_mut_var_assign_decl(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_var_decl_common(ast, idx)
}
fn visit_return(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
let ir = self.ir.push(Inst::Return, None);
Ok(Some(ir))
}
fn visit_return_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::ReturnExprStmt);
let expr = data.as_index();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
let expr = self.visit_any(ast, expr)?.unwrap();
let ir = self
.ir
.push(Inst::ReturnValue(ty), Some(triples::Data::lhs(expr)));
Ok(Some(ir))
}
fn visit_constant(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Constant);
let (ty, value) = data.as_index_intern();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty);
let ir = self.ir.push(Inst::Constant, Some((ty, value).into()));
Ok(Some(ir))
}
fn visit_subscript_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::SubscriptExpr);
let (lhs, index) = data.as_two_indices();
// pointer type
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
let lhs = self.visit_any(ast, lhs)?.unwrap();
let index = self.visit_any(ast, index)?.unwrap();
// TODO: make getelementptr take a variable instead of a constant index.
let ir = self.ir.push(
Inst::GetElementPtr(ty),
Some(triples::Data::new(lhs, index)),
);
Ok(Some(ir))
}
fn visit_call_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::CallExpr);
let (func, arguments) = data.as_two_indices();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
let len = self.visit_parameter_list(ast, arguments)?.unwrap();
_ = self.ir.push(Inst::InlineType(ty), None);
let end = self.ir.nodes.len() as u32;
let func = self.visit_any(ast, func)?.unwrap();
let result = self
.ir
.push(Inst::Call(func), Some(triples::Data::new(end - len, end)));
Ok(Some(result))
}
fn visit_argument(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Argument);
let expr = data.as_index();
let arg = self.visit_any(ast, expr)?.unwrap();
// let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
// self.ir.push(Inst::Argument(ty), Some(triples::Data::lhs(arg)));
Ok(Some(arg))
}
// fn visit_named_argument(
// &mut self,
// ast: &mut super::Ast,
// idx: Index,
// ) -> Result<Self::Value, Self::Error> {
// todo!()
// }
fn visit_argument_list(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::ArgumentList);
let (a, b) = data.as_extra_range();
let args = ast.extra[a..b]
.to_vec()
.into_iter()
.map(|i| Index::from_u32(i).unwrap())
.map(|i| {
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, i);
let arg = self.visit_any_argument(ast, i)?.unwrap();
Ok((ty, arg))
})
.collect::<Result<Vec<_>, _>>()?;
let count = args.len();
for (ty, arg) in args {
_ = self
.ir
.push(Inst::Argument(ty), Some(triples::Data::lhs(arg)));
}
// .try_fold((), |_, e| e.map(crate::unit))?;
Ok(Some(count as u32))
}
fn visit_block_trailing_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::BlockTrailingExpr);
let (a, b) = data.as_extra_range();
let expr = ast.extra[a..b]
.to_vec()
.into_iter()
.map(|i| Index::from_u32(i).unwrap())
.map(|i| self.visit_any(ast, i))
// the last node is the trailing
.try_fold(None, |_, e| e)?;
Ok(expr)
}
fn visit_function_proto(
&mut self,
ast: &mut super::Ast,
idx: super::Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionProto);
let (_, extra) = data.as_intern_and_extra_offset();
let (_return_type, parameter_list) = (
Index::from_u32(ast.extra[extra]).unwrap(),
Index::from_u32(ast.extra[extra + 1]).unwrap(),
);
self.visit_parameter_list(ast, parameter_list)?;
// push parameters to ir
Ok(None)
}
fn visit_parameter_list(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::ParameterList);
let (a, b) = data.as_extra_range();
ast.extra[a..b]
.to_vec()
.into_iter()
.map(|i| Index::from_u32(i).unwrap())
.map(|i| self.visit_parameter(ast, i))
.try_fold((), |_, e| e.map(crate::unit))?;
Ok(None)
}
fn visit_parameter(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Parameter);
let (ty, _name) = data.as_index_intern();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty);
let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO);
let ir = self.ir.push(
Inst::Parameter(ty),
Some(triples::Data::new(info.size(), info.align())),
);
self.ref_lookup.insert(idx, ir);
Ok(None)
}
fn visit_address_of_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::AddressOf);
let expr = data.as_index();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
let expr = self.visit_any(ast, expr)?.unwrap();
let r = self
.ir
.push(Inst::GetElementPtr(ty), Some(triples::Data::new(expr, 0)));
Ok(Some(r))
}
fn visit_assign(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Assign);
let (dst, src) = data.as_two_indices();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
let dst = self.visit_any(ast, dst)?.unwrap();
let src = self.visit_any(ast, src)?.unwrap();
let ir = self
.ir
.push(Inst::Store(ty.into()), Some(triples::Data::new(src, dst)));
Ok(Some(ir))
}
fn visit_explicit_cast_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::ExplicitCast);
let (lhs, ty) = data.as_two_indices();
let lty = ast.get_type_of_node(&self.ip, &mut self.type_cache, lhs);
let rty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty);
let lhs = self.visit_any(ast, lhs)?.unwrap();
// TODO: if bitwidth is the same, then this is a noop?
let cast = self
.ir
.push(Inst::ExplicitCast(lty, rty), Some(triples::Data::lhs(lhs)));
Ok(Some(cast))
}
fn visit_if_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::IfExpr);
let (cond, body) = data.as_two_indices();
let cond = self.visit_any(ast, cond)?.unwrap();
let br = self.ir.push(Inst::Branch(cond), None);
let lbody = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
_ = self.visit_any(ast, body);
let jmp = self.ir.push(Inst::Jump, None);
let skip = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
self.ir.data[br as usize] = Some(triples::Data::new(lbody, skip));
self.ir.data[jmp as usize] = Some(triples::Data::lhs(skip));
Ok(Some(br))
}
fn visit_if_else_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::IfElseExpr);
let (cond, extra) = data.as_index_and_extra_offset();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
let [a, b] = ast.extra[extra..][..2] else {
unreachable!()
};
let cond = self.visit_any(ast, cond)?.unwrap();
let br = self.ir.push(Inst::Branch(cond), None);
let la = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
let a = self.visit_any(ast, Index::from_u32(a).unwrap())?.unwrap();
let jmpa = self.ir.push(Inst::Jump, None);
let lb = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
let b = self.visit_any(ast, Index::from_u32(b).unwrap())?.unwrap();
let jmpb = self.ir.push(Inst::Jump, None);
let lphi = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
let phi = if ty == intern::Index::VOID {
br
} else {
self.ir.push(Inst::Phi2(ty), Some(triples::Data::new(a, b)))
};
self.ir.data[br as usize] = Some(triples::Data::new(la, lb));
self.ir.data[jmpa as usize] = Some(triples::Data::lhs(lphi));
self.ir.data[jmpb as usize] = Some(triples::Data::lhs(lphi));
Ok(Some(phi))
}
fn visit_deref_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Not);
let expr = data.as_index();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
let expr = self.visit_any(ast, expr)?.unwrap();
let not = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr)));
Ok(Some(not))
}
fn visit_not_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Not);
let expr = data.as_index();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
let expr = self.visit_any(ast, expr)?.unwrap();
let not = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(expr)));
Ok(Some(not))
}
fn visit_negate_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Negate);
let expr = data.as_index();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
let expr = self.visit_any(ast, expr)?.unwrap();
let not = self
.ir
.push(Inst::Negate(ty), Some(triples::Data::lhs(expr)));
Ok(Some(not))
}
fn visit_or_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Or);
let (a, b) = data.as_two_indices();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
// TODO: make this an error instead of a panic
let a = self.visit_any(ast, a)?.unwrap();
let not_a = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(a)));
// branch taken if a
let br = self.ir.push(Inst::Branch(not_a), None);
let lb = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
let b = self.visit_any(ast, b)?.unwrap();
let jmp = self.ir.push(Inst::Jump, None);
let la = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
self.ir.data[br as usize] = Some(triples::Data::new(lb, la));
self.ir.data[jmp as usize] = Some(triples::Data::lhs(la));
let or = self.ir.push(
Inst::Phi2(intern::Index::BOOL),
Some(triples::Data::new(a, b)),
);
Ok(Some(or))
}
fn visit_and_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::Or);
let (a, b) = data.as_two_indices();
// TODO: make this an error instead of a panic
let a = self.visit_any(ast, a)?.unwrap();
// branch taken if a
let br = self.ir.push(Inst::Branch(a), None);
let lb = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
let b = self.visit_any(ast, b)?.unwrap();
let skip = self
.ir
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
self.ir.data[br as usize] = Some(triples::Data::new(lb, skip));
let and = self.ir.push(
Inst::Phi2(intern::Index::BOOL),
Some(triples::Data::new(a, b)),
);
Ok(Some(and))
}
fn visit_add_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_sub_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_div_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_rem_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_mul_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_bitand_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_bitor_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_bitxor_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_eq_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_neq_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_lt_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_gt_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_le_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_ge_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_shl_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
fn visit_shr_expr(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_binop_expr(ast, idx)
}
}
impl IrFunctionBuilder<'_> {
fn visit_var_decl_common(
&mut self,
ast: &mut super::Ast,
idx: Index,
) -> Result<Option<u32>, Error> {
let (tag, data) = ast.get_node_tag_and_data(idx);
let (a, b) = data.as_extra_range();
let range = &ast.extra[a..b];
let _name = range.get(0).unwrap();
let (expr, typed_index) = match tag {
super::Tag::VarDecl | super::Tag::MutVarDecl => {
let typed_index = range
.get(1)
.cloned()
.map(Index::from_u32)
.flatten()
.unwrap();
(None, typed_index)
}
super::Tag::VarDeclAssignment | super::Tag::MutVarDeclAssignment => {
let expr = range
.get(1)
.cloned()
.map(Index::from_u32)
.flatten()
.unwrap();
let typed_index = range
.get(2)
.cloned()
.map(Index::from_u32)
.flatten()
.unwrap_or(expr);
(Some(expr), typed_index)
}
_ => unreachable!(),
};
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, typed_index);
let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO);
let alloca = self.ir.push(
Inst::Alloca,
Some(triples::Data::new(info.size(), info.align())),
);
if let Some(idx) = expr {
let expr = self.visit_any(ast, idx)?.unwrap();
_ = self
.ir
.push(Inst::Store(ty), Some(triples::Data::new(expr, alloca)));
}
self.ref_lookup.insert(idx, alloca);
Ok(Some(alloca))
}
/// handles all binary operations that don't short circuit and visit
/// both lhs and rhs.
fn visit_binop_expr(&mut self, ast: &mut super::Ast, idx: Index) -> Result<Option<u32>, Error> {
use triples::Data;
let (tag, data) = ast.get_node_tag_and_data(idx);
let (lhs, rhs) = data.as_two_indices();
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
// TODO: make this an error instead of a panic
let lhs = self.visit_any(ast, lhs)?.unwrap();
let rhs = self.visit_any(ast, rhs)?.unwrap();
let (inst, data) = match tag {
super::Tag::BitOr => (Inst::BitOr(ty), Data::new(lhs, rhs)),
super::Tag::BitXOr => (Inst::BitOr(ty), Data::new(lhs, rhs)),
super::Tag::BitAnd => (Inst::BitOr(ty), Data::new(lhs, rhs)),
super::Tag::Eq => (Inst::Eq(ty), Data::new(lhs, rhs)),
super::Tag::NEq => (Inst::Neq(ty), Data::new(lhs, rhs)),
super::Tag::Lt => (Inst::Lt(ty), Data::new(lhs, rhs)),
super::Tag::Gt => (Inst::Gt(ty), Data::new(lhs, rhs)),
super::Tag::Le => (Inst::Le(ty), Data::new(lhs, rhs)),
super::Tag::Ge => (Inst::Ge(ty), Data::new(lhs, rhs)),
super::Tag::Shl => (Inst::ShiftLeft(ty), Data::new(lhs, rhs)),
super::Tag::Shr => (Inst::ShiftRight(ty), Data::new(lhs, rhs)),
super::Tag::Add => (Inst::Add(ty), Data::new(lhs, rhs)),
super::Tag::Sub => (Inst::Sub(ty), Data::new(lhs, rhs)),
super::Tag::Div => (Inst::Div(ty), Data::new(lhs, rhs)),
super::Tag::Rem => (Inst::Rem(ty), Data::new(lhs, rhs)),
super::Tag::Mul => (Inst::Mul(ty), Data::new(lhs, rhs)),
_ => panic!("not a binop"),
};
Ok(Some(self.ir.push(inst, Some(data))))
}
}
impl AstVisitorTrait for IrBuilder {
type Value = ();
type Error = Error;
const UNIMPL: Self::Error = Error::Unimplemented;
fn visit_function_decl(
&mut self,
ast: &mut super::Ast,
idx: super::Index,
) -> Result<(), Self::Error> {
let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionDecl);
let (proto, block) = data.as_two_indices();
// visit proto
// visit block
todo!()
}
}

File diff suppressed because it is too large Load diff

1915
src/ast2/parser.rs Normal file

File diff suppressed because it is too large Load diff

628
src/ast2/visitor.rs Normal file
View file

@ -0,0 +1,628 @@
use super::*;
pub trait AstExt {
fn get_node_children(&self, node: Index) -> Vec<Index>;
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data);
}
impl AstExt for &Ast {
fn get_node_children(&self, node: Index) -> Vec<Index> {
Ast::get_node_children(self, node)
}
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) {
(self.tags[node], self.datas[node])
}
}
impl AstExt for &mut Ast {
fn get_node_children(&self, node: Index) -> Vec<Index> {
Ast::get_node_children(self, node)
}
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) {
(self.tags[node], self.datas[node])
}
}
pub struct AstVisitor<AstT> {
pub(super) ast: AstT,
pub(super) scopes: Vec<Index>,
pub(super) nodes: Vec<A>,
pub(super) rev: bool,
}
impl<AstT> AstVisitor<AstT>
where
AstT: AstExt,
{
pub fn visit<
F: FnMut(&mut AstT, &[Index], Index, Tag, Data),
G: FnMut(&mut AstT, &[Index], Index, Tag, Data),
>(
&mut self,
mut pre: F,
mut post: G,
) {
while let Some(node) = self.nodes.pop() {
match node {
A::PushChildren(i) => {
self.nodes.push(A::PopSelf(i));
let children_iter = self
.ast
.get_node_children(i)
.into_iter()
.map(|i| A::PushChildren(i));
// inverse because we are popping from the end
if !self.rev {
self.nodes.extend(children_iter.rev())
} else {
self.nodes.extend(children_iter)
};
let (tag, data) = self.ast.get_node_tag_and_data(i);
let _ = pre(&mut self.ast, &self.scopes, i, tag, data);
match tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.push(i);
}
_ => {}
}
}
A::PopSelf(i) => {
// already popped.
let (tag, data) = self.ast.get_node_tag_and_data(i);
let _ = post(&mut self.ast, &self.scopes, i, tag, data);
match tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.pop();
}
_ => {}
}
}
}
}
}
pub fn visit_pre<F: FnMut(&mut AstT, &[Index], Index, Tag, Data)>(&mut self, mut cb: F) {
while let Some(node) = self.nodes.pop() {
match node {
A::PushChildren(i) => {
self.nodes.push(A::PopSelf(i));
let children_iter = self
.ast
.get_node_children(i)
.into_iter()
.map(|i| A::PushChildren(i));
// inverse because we are popping from the end
if !self.rev {
self.nodes.extend(children_iter.rev())
} else {
self.nodes.extend(children_iter)
};
let (tag, data) = self.ast.get_node_tag_and_data(i);
let _ = cb(&mut self.ast, &self.scopes, i, tag, data);
match tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.push(i);
}
_ => {}
}
}
A::PopSelf(i) => {
// already popped.
let (tag, _data) = self.ast.get_node_tag_and_data(i);
match tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.pop();
}
_ => {}
}
}
}
}
}
pub fn visit_post<F: FnMut(&mut AstT, &[Index], Index, Tag, Data)>(&mut self, mut cb: F) {
while let Some(node) = self.nodes.pop() {
match node {
A::PushChildren(i) => {
self.nodes.push(A::PopSelf(i));
let children_iter = self
.ast
.get_node_children(i)
.into_iter()
.map(|i| A::PushChildren(i));
if self.rev {
self.nodes.extend(children_iter.rev())
} else {
self.nodes.extend(children_iter)
};
let (tag, _data) = self.ast.get_node_tag_and_data(i);
match tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.push(i);
}
_ => {}
}
}
A::PopSelf(i) => {
// already popped.
let (tag, data) = self.ast.get_node_tag_and_data(i);
let _ = cb(&mut self.ast, &self.scopes, i, tag, data);
match tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.pop();
}
_ => {}
}
}
}
}
}
}
pub enum A {
PushChildren(Index),
PopSelf(Index),
}
impl Ast {
pub fn visitor_mut(&mut self) -> AstVisitor<&mut Self> {
AstVisitor {
scopes: vec![],
nodes: self
.get_root_file_indices()
.map(|i| visitor::A::PushChildren(i))
.collect(),
ast: self,
rev: false,
}
}
pub fn visitor_rev_mut(&mut self) -> AstVisitor<&mut Self> {
AstVisitor {
scopes: vec![],
nodes: self
.get_root_file_indices()
.map(|i| visitor::A::PushChildren(i))
.collect(),
ast: self,
rev: true,
}
}
pub fn visitor(&self) -> AstVisitor<&Self> {
AstVisitor {
scopes: vec![],
nodes: self
.get_root_file_indices()
.map(|i| visitor::A::PushChildren(i))
.collect(),
ast: self,
rev: false,
}
}
}
impl Ast {
pub fn visit_all_functions_mut<V>(&mut self, visitor: &mut impl AstVisitorTrait) {
for i in
(0..self.tags.functions.len()).map(|i| Index::new(Kind::Function, i as u32).unwrap())
{
visitor.visit_function_decl(self, i);
}
}
pub fn visit_function_mut<F: FnMut(&mut Self)>(&mut self) {}
}
pub trait AstVisitorTrait {
type Error;
type Value;
const UNIMPL: Self::Error;
fn visit_function_decl(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_parameter(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_parameter_list(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_block(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_block_trailing_expr(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_block_maybe_trailing(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
use visitor::AstExt;
match ast.get_node_tag_and_data(idx).0 {
Tag::BlockTrailingExpr => self.visit_block(ast, idx),
Tag::Block => self.visit_block_trailing_expr(ast, idx),
_ => unreachable!(),
}
}
fn visit_function_proto(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_call_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_add_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_sub_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_mul_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_div_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_rem_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_eq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_neq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_lt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_gt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_le_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_ge_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_shl_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_shr_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_bitor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_bitxor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_bitand_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_or_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_and_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_not_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_negate_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_deref_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_address_of_expr(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_explicit_cast_expr(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_assign(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_subscript_expr(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_if_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_if_else_expr(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_argument(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_any_argument(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
use visitor::AstExt;
match ast.get_node_tag_and_data(idx).0 {
Tag::Argument => self.visit_argument(ast, idx),
Tag::NamedArgument => self.visit_named_argument(ast, idx),
_ => unreachable!(),
}
}
fn visit_named_argument(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_argument_list(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_constant(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_return(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_return_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_global_decl(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_var_decl(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_mut_var_decl(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_var_assign_decl(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_mut_var_assign_decl(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_decl_ref(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
_ = (ast, idx);
Err(Self::UNIMPL)
}
fn visit_value_to_place_conversion(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let idx = ast
.get_node_data_for_tag(idx, Tag::ValueToPlaceConversion)
.unwrap()
.as_index();
self.visit_any(ast, idx)
}
fn visit_place_to_value_conversion(
&mut self,
ast: &mut Ast,
idx: Index,
) -> Result<Self::Value, Self::Error> {
let idx = ast
.get_node_data_for_tag(idx, Tag::PlaceToValueConversion)
.unwrap()
.as_index();
self.visit_any(ast, idx)
}
fn visit_any(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
use visitor::AstExt;
match ast.get_node_tag_and_data(idx).0 {
Tag::FunctionProto => self.visit_function_proto(ast, idx),
Tag::FunctionDecl => self.visit_function_decl(ast, idx),
Tag::ParameterList => self.visit_parameter_list(ast, idx),
Tag::Parameter => self.visit_parameter(ast, idx),
Tag::Block => self.visit_block(ast, idx),
Tag::BlockTrailingExpr => self.visit_block_trailing_expr(ast, idx),
Tag::Constant => self.visit_constant(ast, idx),
Tag::ExprStmt => todo!(),
Tag::ReturnStmt => self.visit_return(ast, idx),
Tag::ReturnExprStmt => self.visit_return_expr(ast, idx),
Tag::VarDecl => self.visit_var_decl(ast, idx),
Tag::MutVarDecl => self.visit_mut_var_decl(ast, idx),
Tag::VarDeclAssignment => self.visit_var_assign_decl(ast, idx),
Tag::MutVarDeclAssignment => self.visit_mut_var_assign_decl(ast, idx),
Tag::GlobalDecl => self.visit_global_decl(ast, idx),
Tag::StructDecl => todo!(),
Tag::FieldDecl => todo!(),
Tag::DeclRef => self.visit_decl_ref(ast, idx),
Tag::DeclRefUnresolved => todo!(),
Tag::InternedType => todo!(),
Tag::TypeDeclRef => todo!(),
Tag::TypeDeclRefUnresolved => todo!(),
Tag::PointerType => todo!(),
Tag::ArrayType => todo!(),
Tag::CallExpr => self.visit_call_expr(ast, idx),
Tag::FieldAccess => todo!(),
Tag::ArgumentList => self.visit_argument_list(ast, idx),
Tag::Argument => self.visit_argument(ast, idx),
Tag::NamedArgument => self.visit_named_argument(ast, idx),
Tag::ExplicitCast => self.visit_explicit_cast_expr(ast, idx),
Tag::Deref => self.visit_deref_expr(ast, idx),
Tag::AddressOf => self.visit_add_expr(ast, idx),
Tag::Not => self.visit_not_expr(ast, idx),
Tag::Negate => self.visit_negate_expr(ast, idx),
Tag::Or => self.visit_or_expr(ast, idx),
Tag::And => self.visit_and_expr(ast, idx),
Tag::BitOr => self.visit_bitor_expr(ast, idx),
Tag::BitXOr => self.visit_bitxor_expr(ast, idx),
Tag::BitAnd => self.visit_bitand_expr(ast, idx),
Tag::Eq => self.visit_eq_expr(ast, idx),
Tag::NEq => self.visit_neq_expr(ast, idx),
Tag::Lt => self.visit_lt_expr(ast, idx),
Tag::Gt => self.visit_gt_expr(ast, idx),
Tag::Le => self.visit_le_expr(ast, idx),
Tag::Ge => self.visit_ge_expr(ast, idx),
Tag::Shl => self.visit_shl_expr(ast, idx),
Tag::Shr => self.visit_shr_expr(ast, idx),
Tag::Add => self.visit_add_expr(ast, idx),
Tag::Sub => self.visit_sub_expr(ast, idx),
Tag::Mul => self.visit_mul_expr(ast, idx),
Tag::Div => self.visit_div_expr(ast, idx),
Tag::Rem => self.visit_rem_expr(ast, idx),
Tag::Assign => self.visit_assign(ast, idx),
Tag::SubscriptExpr => self.visit_subscript_expr(ast, idx),
Tag::IfExpr => self.visit_if_expr(ast, idx),
Tag::IfElseExpr => self.visit_if_else_expr(ast, idx),
Tag::PlaceToValueConversion => self.visit_place_to_value_conversion(ast, idx),
Tag::ValueToPlaceConversion => self.visit_value_to_place_conversion(ast, idx),
Tag::Error => todo!(),
Tag::Undefined => todo!(),
Tag::Root => todo!(),
Tag::File => todo!(),
}
}
}
impl Ast {
pub fn get_node_data_for_tag(&self, idx: Index, tag: Tag) -> Option<Data> {
use visitor::AstExt;
let (t, data) = self.get_node_tag_and_data(idx);
if t == tag {
Some(data)
} else {
None
}
}
pub fn expect_node_data_for_tag(&self, idx: Index, tag: Tag) -> Data {
self.get_node_data_for_tag(idx, tag)
.expect(&format!("node {idx} is not a {tag:?}"))
}
}

View file

@ -55,7 +55,7 @@ fn main() {
println!("AST:\n{buf}"); println!("AST:\n{buf}");
} }
"ast2" => { "ast2" => {
let mut tree2 = compiler::ast2::ast_gen::Parser::new(); let mut tree2 = compiler::ast2::parser::Parser::new();
tree2.parse(tokens.iter()); tree2.parse(tokens.iter());
eprintln!("{tree2:#?}"); eprintln!("{tree2:#?}");
println!("AST (new):\n{tree2}"); println!("AST (new):\n{tree2}");