Compare commits
15 commits
main
...
bottom-up-
Author | SHA1 | Date | |
---|---|---|---|
|
aeab786fe3 | ||
|
4c7813aa98 | ||
|
1bde8f3ccd | ||
|
486a634ea1 | ||
|
8b3789d7b0 | ||
|
d6450b5f32 | ||
|
f30b7827b8 | ||
|
6cc1822ec6 | ||
|
8c95a2ba3d | ||
|
f5fc8195f4 | ||
|
1be3f29e23 | ||
|
6d70231c91 | ||
|
51aa119af2 | ||
|
028c74753e | ||
|
1a20acd763 |
|
@ -12,6 +12,7 @@ log = "0.4.22"
|
|||
num-bigint = "0.4.6"
|
||||
num-traits = "0.2.19"
|
||||
ordered-float = "4.2.2"
|
||||
paste = "1.0.15"
|
||||
petgraph = "0.6.5"
|
||||
thiserror = "1.0.63"
|
||||
unicode-xid = "0.2.4"
|
||||
|
|
159
src/ast2/debug.rs
Normal file
159
src/ast2/debug.rs
Normal file
|
@ -0,0 +1,159 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use crate::{lexer::SourceLocation, writeln_indented};
|
||||
|
||||
use super::{
|
||||
intern::{self, InternPoolWrapper as InternPool},
|
||||
visitor::AstVisitorTrait,
|
||||
Ast, Children, ComptimeCache, Index, Tag, TypeCache,
|
||||
};
|
||||
|
||||
struct AstRenderVisitor<'a, W: core::fmt::Write> {
|
||||
syms: &'a crate::symbol_table::syms2::Symbols,
|
||||
ip: &'a InternPool,
|
||||
cache: TypeCache,
|
||||
comptime_cache: ComptimeCache,
|
||||
scopes: Vec<Index>,
|
||||
w: &'a mut W,
|
||||
}
|
||||
|
||||
impl<'a, W: core::fmt::Write> AstVisitorTrait<&'a Ast> for AstRenderVisitor<'_, W> {
|
||||
type Error = core::fmt::Error;
|
||||
|
||||
type Value = ();
|
||||
|
||||
const UNIMPL: Self::Error = core::fmt::Error;
|
||||
|
||||
fn visit_any(&mut self, ast: &'a Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
||||
let display = NodeDisplay::new(ast, self.ip, idx).with_indent(self.scopes.len() as u32 * 2);
|
||||
|
||||
match display.tag {
|
||||
Tag::File
|
||||
| Tag::FunctionDecl
|
||||
| Tag::GlobalDecl
|
||||
| Tag::Block
|
||||
| Tag::BlockTrailingExpr => {
|
||||
self.scopes.push(idx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
write!(self.w, "{display}")?;
|
||||
|
||||
for child in display.children.0 {
|
||||
self.visit_any(ast, child)?;
|
||||
}
|
||||
|
||||
match display.tag {
|
||||
Tag::File
|
||||
| Tag::FunctionDecl
|
||||
| Tag::GlobalDecl
|
||||
| Tag::Block
|
||||
| Tag::BlockTrailingExpr => {
|
||||
self.scopes.pop();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AstRenderer<'a> {
|
||||
ast: &'a Ast,
|
||||
#[allow(dead_code)]
|
||||
syms: &'a crate::symbol_table::syms2::Symbols,
|
||||
ip: &'a InternPool,
|
||||
cache: TypeCache,
|
||||
comptime_cache: ComptimeCache,
|
||||
}
|
||||
|
||||
pub struct NodeDisplay {
|
||||
node: Index,
|
||||
tag: Tag,
|
||||
loc: SourceLocation,
|
||||
children: Children,
|
||||
is_comptime: bool,
|
||||
ty: intern::Index,
|
||||
indent: u32,
|
||||
}
|
||||
|
||||
impl NodeDisplay {
|
||||
pub fn new(ast: &Ast, ip: &InternPool, node: Index) -> NodeDisplay {
|
||||
let tag = ast.tags[node];
|
||||
let loc = ast.source_locs[node];
|
||||
|
||||
let children = Children(ast.get_node_children(node));
|
||||
let ty = ast.get_type_of_node(ip, &mut TypeCache::new(), node);
|
||||
|
||||
let is_comptime = ast.is_node_comptime_evaluable(&mut ComptimeCache::default(), node);
|
||||
|
||||
Self {
|
||||
node,
|
||||
tag,
|
||||
loc,
|
||||
children,
|
||||
is_comptime,
|
||||
ty,
|
||||
indent: 0,
|
||||
}
|
||||
}
|
||||
fn with_indent(self, indent: u32) -> Self {
|
||||
Self { indent, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for NodeDisplay {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self {
|
||||
node,
|
||||
tag,
|
||||
loc,
|
||||
children,
|
||||
is_comptime,
|
||||
ty,
|
||||
indent,
|
||||
} = self;
|
||||
writeln_indented!(
|
||||
*indent,
|
||||
f,
|
||||
"{node} {}({ty}) = ({loc}) {tag:?} {children}",
|
||||
if *is_comptime { "CONST " } else { "" }
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
cache: TypeCache::new(),
|
||||
comptime_cache: ComptimeCache::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn render<W: core::fmt::Write>(&mut self, w: &mut W) -> core::fmt::Result {
|
||||
let mut visitor = AstRenderVisitor {
|
||||
syms: self.syms,
|
||||
ip: self.ip,
|
||||
cache: TypeCache::new(),
|
||||
comptime_cache: ComptimeCache::default(),
|
||||
scopes: Vec::new(),
|
||||
w,
|
||||
};
|
||||
|
||||
for idx in self.ast.get_root_file_indices() {
|
||||
visitor.visit_any(self.ast, idx)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -402,6 +402,73 @@ impl Index {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct InternPoolWrapper(core::cell::UnsafeCell<InternPool>);
|
||||
|
||||
impl InternPoolWrapper {
|
||||
pub fn as_mut(&self) -> &mut InternPool {
|
||||
unsafe { &mut *self.0.get() }
|
||||
}
|
||||
pub fn as_ref(&self) -> &InternPool {
|
||||
unsafe { &*self.0.get() }
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
InternPool::new().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InternPool> for InternPoolWrapper {
|
||||
fn from(value: InternPool) -> Self {
|
||||
Self(core::cell::UnsafeCell::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Deref for InternPoolWrapper {
|
||||
type Target = InternPool;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.0.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::DerefMut for InternPoolWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<InternPool> for InternPoolWrapper {
|
||||
fn as_ref(&self) -> &InternPool {
|
||||
Self::as_ref(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<InternPool> for InternPool {
|
||||
fn as_ref(&self) -> &InternPool {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// impl AsMut<InternPool> for InternPoolWrapper {
|
||||
// fn as_mut(&mut self) -> &mut InternPool {
|
||||
// Self::as_mut(self)
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl AsMut<InternPool> for InternPool {
|
||||
// fn as_mut(&mut self) -> &mut InternPool {
|
||||
// self
|
||||
// }
|
||||
// }
|
||||
|
||||
impl core::fmt::Debug for InternPoolWrapper {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("InternPoolWrapper")
|
||||
.field(self.as_ref())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InternPool {
|
||||
tags: Vec<Tag>,
|
||||
indices: Vec<u32>,
|
||||
|
@ -574,6 +641,17 @@ pub struct TypeInfo {
|
|||
pub signed: bool,
|
||||
}
|
||||
|
||||
impl TypeInfo {
|
||||
/// byte size
|
||||
pub fn size(&self) -> u32 {
|
||||
self.bitsize.div_ceil(8)
|
||||
}
|
||||
/// byte align
|
||||
pub fn align(&self) -> u32 {
|
||||
self.bitalign.div_ceil(8)
|
||||
}
|
||||
}
|
||||
|
||||
impl InternPool {
|
||||
pub fn peer_type(&mut self, lhs: Index, rhs: Index) -> Option<Index> {
|
||||
if lhs == rhs {
|
||||
|
@ -1297,6 +1375,20 @@ impl InternPool {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn try_get_pointee_type(&self, pointer: Index) -> Option<Index> {
|
||||
match self.get_key(pointer) {
|
||||
Key::PointerType { pointee, .. } | Key::ArrayType { pointee, .. } => Some(pointee),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get_return_type(&self, func: Index) -> Option<Index> {
|
||||
match self.get_key(func) {
|
||||
Key::FunctionType { return_type, .. } => Some(return_type),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_type(&mut self, pointee: Index, flags: Option<PointerFlags>) -> Index {
|
||||
let key = Key::PointerType {
|
||||
pointee,
|
||||
|
@ -1304,6 +1396,7 @@ impl InternPool {
|
|||
};
|
||||
self.get_or_insert(key)
|
||||
}
|
||||
|
||||
pub fn try_get_pointer_type(
|
||||
&self,
|
||||
pointee: Index,
|
||||
|
|
1232
src/ast2/ir.rs
Normal file
1232
src/ast2/ir.rs
Normal file
File diff suppressed because it is too large
Load diff
2599
src/ast2/mod.rs
2599
src/ast2/mod.rs
File diff suppressed because it is too large
Load diff
1906
src/ast2/parser.rs
Normal file
1906
src/ast2/parser.rs
Normal file
File diff suppressed because it is too large
Load diff
631
src/ast2/tag.rs
Normal file
631
src/ast2/tag.rs
Normal file
|
@ -0,0 +1,631 @@
|
|||
use super::{
|
||||
intern::{Index as Interned, PointerFlags, StructFlags},
|
||||
visitor::AstExt,
|
||||
Ast, Index, ParseError, Tag,
|
||||
};
|
||||
|
||||
pub trait AstNodeExt {
|
||||
fn get_ast_node(&self, idx: Index) -> AstNode;
|
||||
}
|
||||
|
||||
impl AstNodeExt for &mut Ast {
|
||||
fn get_ast_node(&self, idx: Index) -> AstNode {
|
||||
<Ast as AstNodeExt>::get_ast_node(self, idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl AstNodeExt for &Ast {
|
||||
fn get_ast_node(&self, idx: Index) -> AstNode {
|
||||
<Ast as AstNodeExt>::get_ast_node(self, idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl AstNodeExt for Ast {
|
||||
fn get_ast_node(&self, idx: Index) -> AstNode {
|
||||
let (tag, data) = self.get_node_tag_and_data(idx);
|
||||
|
||||
match tag {
|
||||
Tag::Root => {
|
||||
unreachable!()
|
||||
}
|
||||
Tag::File => {
|
||||
let (a, b) = data.as_extra_range();
|
||||
let decls = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
|
||||
|
||||
AstNode::File { decls }
|
||||
}
|
||||
Tag::FunctionProto => {
|
||||
let (name, extra) = data.as_intern_and_extra_offset();
|
||||
|
||||
let (return_type, parameter_list) = (
|
||||
Index::from_u32(self.extra[extra]).unwrap(),
|
||||
Index::from_u32(self.extra[extra + 1]).unwrap(),
|
||||
);
|
||||
|
||||
AstNode::FunctionProto {
|
||||
name,
|
||||
return_type,
|
||||
parameter_list,
|
||||
}
|
||||
}
|
||||
Tag::FunctionProtoInterned => {
|
||||
let (name, ty) = data.as_two_interns();
|
||||
AstNode::FunctionProtoInterned { name, ty }
|
||||
}
|
||||
Tag::FunctionDecl => {
|
||||
let (proto, body) = data.as_two_indices();
|
||||
|
||||
AstNode::FunctionDecl { proto, body }
|
||||
}
|
||||
Tag::ParameterList => {
|
||||
let (a, b) = data.as_extra_range();
|
||||
let params = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
|
||||
|
||||
AstNode::ParameterList { params }
|
||||
}
|
||||
Tag::Parameter => {
|
||||
let (ty, name) = data.as_index_intern();
|
||||
|
||||
AstNode::Parameter { ty, name }
|
||||
}
|
||||
Tag::Block => {
|
||||
let (a, b) = data.as_extra_range();
|
||||
let statements = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
|
||||
|
||||
AstNode::Block {
|
||||
statements,
|
||||
expr: None,
|
||||
}
|
||||
}
|
||||
Tag::BlockTrailingExpr => {
|
||||
let (a, b) = data.as_extra_range();
|
||||
let (expr, statements) = unsafe {
|
||||
Index::from_slice_unchecked(&self.extra[a..b])
|
||||
.split_last()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
AstNode::Block {
|
||||
statements: statements.to_vec(),
|
||||
expr: Some(*expr),
|
||||
}
|
||||
}
|
||||
Tag::Constant => {
|
||||
let (ty, value) = data.as_index_intern();
|
||||
AstNode::Constant { ty, value }
|
||||
}
|
||||
Tag::ExprStmt => AstNode::ExprStmt {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::ReturnStmt => AstNode::ReturnStmt,
|
||||
Tag::ReturnExprStmt => AstNode::ReturnExprStmt {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::VarDecl => {
|
||||
let (a, _) = data.as_extra_range();
|
||||
let name = Interned::from_u32(self.extra[a]);
|
||||
let ty = Index::from_u32(self.extra[a + 1]).unwrap();
|
||||
|
||||
AstNode::VarDecl { name, ty }
|
||||
}
|
||||
Tag::MutVarDecl => {
|
||||
let (a, _) = data.as_extra_range();
|
||||
let name = Interned::from_u32(self.extra[a]);
|
||||
let ty = Index::from_u32(self.extra[a + 1]).unwrap();
|
||||
|
||||
AstNode::MutVarDecl { name, ty }
|
||||
}
|
||||
Tag::VarDeclAssignment => {
|
||||
let (a, b) = data.as_extra_range();
|
||||
let extra = &self.extra[a..b];
|
||||
let name = Interned::from_u32(*extra.get(0).unwrap());
|
||||
let expr = Index::from_u32(*extra.get(1).unwrap()).unwrap();
|
||||
let ty = extra.get(2).map(|&inner| Index::from_u32(inner).unwrap());
|
||||
|
||||
AstNode::MutVarDeclAssignment { name, expr, ty }
|
||||
}
|
||||
Tag::MutVarDeclAssignment => {
|
||||
let (a, b) = data.as_extra_range();
|
||||
let extra = &self.extra[a..b];
|
||||
let name = Interned::from_u32(*extra.get(0).unwrap());
|
||||
let expr = Index::from_u32(*extra.get(1).unwrap()).unwrap();
|
||||
let ty = extra.get(2).map(|&inner| Index::from_u32(inner).unwrap());
|
||||
|
||||
AstNode::MutVarDeclAssignment { name, expr, ty }
|
||||
}
|
||||
Tag::GlobalDecl => {
|
||||
let (name, offset) = data.as_intern_and_extra_offset();
|
||||
let ty = Index::from_u32(self.extra[offset]).unwrap();
|
||||
let expr = Index::from_u32(self.extra[offset + 1]).unwrap();
|
||||
|
||||
AstNode::GlobalDecl { name, expr, ty }
|
||||
}
|
||||
Tag::StructDecl => {
|
||||
let (name, offset) = data.as_intern_and_extra_offset();
|
||||
let flags = StructFlags::unpack(self.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 field_types =
|
||||
unsafe { Index::from_slice_unchecked(&self.extra[types]).to_vec() };
|
||||
|
||||
let field_names = self.extra[names]
|
||||
.iter()
|
||||
.map(|&i| Interned::from_u32(i))
|
||||
.collect();
|
||||
|
||||
AstNode::StructDecl {
|
||||
name,
|
||||
flags,
|
||||
field_names,
|
||||
field_types,
|
||||
}
|
||||
}
|
||||
Tag::StructDeclInterned => {
|
||||
let (name, ty) = data.as_two_interns();
|
||||
|
||||
AstNode::StructDeclInterned { name, ty }
|
||||
}
|
||||
Tag::FieldDecl => {
|
||||
let (ty, name) = data.as_index_intern();
|
||||
|
||||
AstNode::FieldDecl { name, ty }
|
||||
}
|
||||
Tag::DeclRef => AstNode::DeclRef {
|
||||
decl: data.as_index(),
|
||||
},
|
||||
Tag::DeclRefUnresolved => {
|
||||
let (scope, name) = data.as_index_intern();
|
||||
AstNode::DeclRefUnresolved { scope, name }
|
||||
}
|
||||
Tag::InternedType => AstNode::InternedType {
|
||||
intern: data.as_intern(),
|
||||
},
|
||||
Tag::TypeDeclRef => AstNode::TypeDeclRef {
|
||||
decl: data.as_index(),
|
||||
},
|
||||
Tag::TypeDeclRefUnresolved => {
|
||||
let (scope, name) = data.as_index_intern();
|
||||
AstNode::TypeDeclRefUnresolved { scope, name }
|
||||
}
|
||||
Tag::PointerType => {
|
||||
let (ty, flags) = data.as_index_and_opaque();
|
||||
let flags = PointerFlags::unpack(flags as u8);
|
||||
AstNode::PointerType { ty, flags }
|
||||
}
|
||||
Tag::ArrayType => {
|
||||
let (length, pointer) = data.as_two_indices();
|
||||
|
||||
AstNode::ArrayType { length, pointer }
|
||||
}
|
||||
Tag::CallExpr => {
|
||||
let (func, argument_list) = data.as_two_indices();
|
||||
AstNode::CallExpr {
|
||||
func,
|
||||
argument_list,
|
||||
}
|
||||
}
|
||||
Tag::FieldAccess => {
|
||||
let (expr, field_name) = data.as_index_intern();
|
||||
AstNode::FieldAccess { field_name, expr }
|
||||
}
|
||||
Tag::ArgumentList => {
|
||||
let (a, b) = data.as_extra_range();
|
||||
let arguments = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
|
||||
|
||||
AstNode::ArgumentList { arguments }
|
||||
}
|
||||
Tag::Argument => AstNode::Argument {
|
||||
expr: data.as_index(),
|
||||
name: None,
|
||||
},
|
||||
Tag::NamedArgument => {
|
||||
let (expr, name) = data.as_index_intern();
|
||||
AstNode::Argument {
|
||||
expr,
|
||||
name: Some(name),
|
||||
}
|
||||
}
|
||||
Tag::ExplicitCast => {
|
||||
let (expr, ty) = data.as_two_indices();
|
||||
|
||||
AstNode::ExplicitCast { expr, ty }
|
||||
}
|
||||
Tag::Deref => AstNode::Deref {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::AddressOf => AstNode::AddressOf {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::Not => AstNode::Not {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::Negate => AstNode::Negate {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::PlaceToValueConversion => AstNode::PlaceToValueConversion {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::ValueToPlaceConversion => AstNode::ValueToPlaceConversion {
|
||||
expr: data.as_index(),
|
||||
},
|
||||
Tag::Or => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Or { lhs, rhs }
|
||||
}
|
||||
Tag::And => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::And { lhs, rhs }
|
||||
}
|
||||
Tag::BitOr => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::BitOr { lhs, rhs }
|
||||
}
|
||||
Tag::BitXOr => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::BitXOr { lhs, rhs }
|
||||
}
|
||||
Tag::BitAnd => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::BitAnd { lhs, rhs }
|
||||
}
|
||||
Tag::Eq => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Eq { lhs, rhs }
|
||||
}
|
||||
Tag::NEq => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::NEq { lhs, rhs }
|
||||
}
|
||||
Tag::Lt => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Lt { lhs, rhs }
|
||||
}
|
||||
Tag::Gt => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Gt { lhs, rhs }
|
||||
}
|
||||
Tag::Le => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Le { lhs, rhs }
|
||||
}
|
||||
Tag::Ge => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Ge { lhs, rhs }
|
||||
}
|
||||
Tag::Shl => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Shl { lhs, rhs }
|
||||
}
|
||||
Tag::Shr => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Shr { lhs, rhs }
|
||||
}
|
||||
Tag::Add => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Add { lhs, rhs }
|
||||
}
|
||||
Tag::Sub => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Sub { lhs, rhs }
|
||||
}
|
||||
Tag::Mul => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Mul { lhs, rhs }
|
||||
}
|
||||
Tag::Div => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Div { lhs, rhs }
|
||||
}
|
||||
Tag::Rem => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Rem { lhs, rhs }
|
||||
}
|
||||
Tag::Assign => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
AstNode::Assign { lhs, rhs }
|
||||
}
|
||||
Tag::SubscriptExpr => {
|
||||
let (lhs, index) = data.as_two_indices();
|
||||
AstNode::SubscriptExpr { lhs, index }
|
||||
}
|
||||
Tag::IfExpr => {
|
||||
let (cond, body) = data.as_two_indices();
|
||||
AstNode::IfExpr { cond, body }
|
||||
}
|
||||
Tag::IfElseExpr => {
|
||||
let (cond, extra) = data.as_index_and_extra_offset();
|
||||
let [a, b] = self.extra[extra..][..2] else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
AstNode::IfElseExpr {
|
||||
cond,
|
||||
a: Index::from_u32(a).unwrap(),
|
||||
b: Index::from_u32(b).unwrap(),
|
||||
}
|
||||
}
|
||||
Tag::Error => AstNode::Error {
|
||||
err: data.as_error(),
|
||||
},
|
||||
Tag::Undefined => AstNode::Undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum AstNode {
|
||||
/// pseudo tag, contains a range from a..b into extra of all files.
|
||||
Root {
|
||||
files: Vec<Index>,
|
||||
},
|
||||
/// `data` is a range from a..b into extra of all global nodes.
|
||||
File {
|
||||
decls: Vec<Index>,
|
||||
},
|
||||
/// `data` is an intern to a name, and an index into extra of [index: return_type, index: ParameterList]
|
||||
FunctionProto {
|
||||
name: Interned,
|
||||
return_type: Index,
|
||||
parameter_list: Index,
|
||||
},
|
||||
/// `data` is an intern to a name, and an intern to the function type
|
||||
FunctionProtoInterned {
|
||||
name: Interned,
|
||||
ty: Interned,
|
||||
},
|
||||
/// `data` is an index to a FunctionProto and an index to a Block
|
||||
FunctionDecl {
|
||||
proto: Index,
|
||||
body: Index,
|
||||
},
|
||||
/// `data` is a range from a..b into extra of indices to parameters
|
||||
ParameterList {
|
||||
params: Vec<Index>,
|
||||
},
|
||||
/// `data` is an index to a type, and an intern to a name
|
||||
Parameter {
|
||||
ty: Index,
|
||||
name: Interned,
|
||||
},
|
||||
/// `data` is range from a..b into `extra` of indices to statements
|
||||
Block {
|
||||
statements: Vec<Index>,
|
||||
expr: Option<Index>,
|
||||
},
|
||||
/// `data` is an index to a type, and an intern to a value
|
||||
Constant {
|
||||
ty: Index,
|
||||
value: Interned,
|
||||
},
|
||||
/// `data` is an index to an expression
|
||||
ExprStmt {
|
||||
expr: Index,
|
||||
},
|
||||
/// `data` is none
|
||||
ReturnStmt,
|
||||
/// `data` is an index to an expr
|
||||
ReturnExprStmt {
|
||||
expr: Index,
|
||||
},
|
||||
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
|
||||
VarDecl {
|
||||
name: Interned,
|
||||
ty: Index,
|
||||
},
|
||||
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
|
||||
MutVarDecl {
|
||||
name: Interned,
|
||||
ty: Index,
|
||||
},
|
||||
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
|
||||
VarDeclAssignment {
|
||||
name: Interned,
|
||||
expr: Index,
|
||||
ty: Option<Index>,
|
||||
},
|
||||
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
|
||||
MutVarDeclAssignment {
|
||||
name: Interned,
|
||||
expr: Index,
|
||||
ty: Option<Index>,
|
||||
},
|
||||
/// `data` is an intern to a name, and an offset into `extra` of `[type: index, expr: index]`
|
||||
GlobalDecl {
|
||||
name: Interned,
|
||||
expr: Index,
|
||||
ty: Index,
|
||||
},
|
||||
/// `data` is an intern to a name, and an offset into extra of `[flags, type0 ,..., typeN ,name0 ,..., nameN]`
|
||||
StructDecl {
|
||||
name: Interned,
|
||||
flags: StructFlags,
|
||||
field_names: Vec<Interned>,
|
||||
field_types: Vec<Index>,
|
||||
},
|
||||
/// `data` is an intern to a name, and an intern to the type of the struct
|
||||
StructDeclInterned {
|
||||
name: Interned,
|
||||
ty: Interned,
|
||||
},
|
||||
/// `data` is an index to a type, and an intern to a name
|
||||
FieldDecl {
|
||||
name: Interned,
|
||||
ty: Index,
|
||||
},
|
||||
/// `data` is an index to a Parameter, VarDecl, GlobalDecl or FunctionDecl, and an opaque DeclKind
|
||||
DeclRef {
|
||||
decl: Index,
|
||||
},
|
||||
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
|
||||
DeclRefUnresolved {
|
||||
scope: Index,
|
||||
name: Interned,
|
||||
},
|
||||
/// `data` is an intern of a type
|
||||
InternedType {
|
||||
intern: Interned,
|
||||
},
|
||||
/// `data` is an index to a StructDecl
|
||||
TypeDeclRef {
|
||||
decl: Index,
|
||||
},
|
||||
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
|
||||
TypeDeclRefUnresolved {
|
||||
scope: Index,
|
||||
name: Interned,
|
||||
},
|
||||
/// `data` is an index to a Type and u32 PointerFlags (extra offset)
|
||||
PointerType {
|
||||
ty: Index,
|
||||
flags: PointerFlags,
|
||||
},
|
||||
/// `data` is an index to a length expression, and an underlying pointer type
|
||||
ArrayType {
|
||||
length: Index,
|
||||
pointer: Index,
|
||||
},
|
||||
/// `data` is an index to an expr and an index to an ArgumentList
|
||||
CallExpr {
|
||||
func: Index,
|
||||
argument_list: Index,
|
||||
},
|
||||
/// `data` is an index to an expr and an intern to a field name
|
||||
FieldAccess {
|
||||
field_name: Interned,
|
||||
expr: Index,
|
||||
},
|
||||
/// `data` is a range from a..b into extra of indices to arguments
|
||||
ArgumentList {
|
||||
arguments: Vec<Index>,
|
||||
},
|
||||
/// `data` is an index to an expression
|
||||
Argument {
|
||||
expr: Index,
|
||||
name: Option<Interned>,
|
||||
},
|
||||
/// `data` is an index to lhs, and an index to the type
|
||||
ExplicitCast {
|
||||
expr: Index,
|
||||
ty: Index,
|
||||
},
|
||||
/// `data` is a single index to an expr
|
||||
Deref {
|
||||
expr: Index,
|
||||
},
|
||||
AddressOf {
|
||||
expr: Index,
|
||||
},
|
||||
Not {
|
||||
expr: Index,
|
||||
},
|
||||
Negate {
|
||||
expr: Index,
|
||||
},
|
||||
PlaceToValueConversion {
|
||||
expr: Index,
|
||||
},
|
||||
ValueToPlaceConversion {
|
||||
expr: Index,
|
||||
},
|
||||
/// data is two indices for `lhs` and `rhs`
|
||||
Or {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
And {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
BitOr {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
BitXOr {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
BitAnd {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Eq {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
NEq {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Lt {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Gt {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Le {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Ge {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Shl {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Shr {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Add {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Sub {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Mul {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Div {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Rem {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Assign {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
SubscriptExpr {
|
||||
lhs: Index,
|
||||
index: Index,
|
||||
},
|
||||
IfExpr {
|
||||
cond: Index,
|
||||
body: Index,
|
||||
},
|
||||
/// `data` is an index to an expression and an index into extra for [if, else]
|
||||
IfElseExpr {
|
||||
cond: Index,
|
||||
a: Index,
|
||||
b: Index,
|
||||
},
|
||||
// TODO:
|
||||
/// `data` is a ParseError
|
||||
Error {
|
||||
err: ParseError,
|
||||
},
|
||||
/// placeholder tag for reserved indices/nodes, `data` is none
|
||||
Undefined,
|
||||
}
|
499
src/ast2/typecheck.rs
Normal file
499
src/ast2/typecheck.rs
Normal file
|
@ -0,0 +1,499 @@
|
|||
use crate::variant;
|
||||
|
||||
use super::{
|
||||
intern::{self},
|
||||
tag::{AstNode, AstNodeExt},
|
||||
visitor::{AstExt, AstVisitorTrait},
|
||||
Ast, Data, Index, Tag,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum ErrorKind {
|
||||
MismatchingTypes,
|
||||
DerefNonPointer,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct Error {
|
||||
idx: Index,
|
||||
kind: ErrorKind,
|
||||
}
|
||||
|
||||
struct TypeChecker<'a> {
|
||||
ip: &'a mut intern::InternPool,
|
||||
errors: Vec<Error>,
|
||||
}
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
fn visit_children<'b>(
|
||||
&mut self,
|
||||
ast: &'b mut super::Ast,
|
||||
idx: Index,
|
||||
) -> Result<Option<intern::Index>, ()> {
|
||||
for child in ast.get_node_children(idx) {
|
||||
self.visit_any(ast, child)?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: actually handle errors here instead of aborting.
|
||||
impl<'a> AstVisitorTrait<&'a mut Ast> for TypeChecker<'_> {
|
||||
type Error = ();
|
||||
|
||||
type Value = Option<intern::Index>;
|
||||
|
||||
const UNIMPL: Self::Error = ();
|
||||
|
||||
fn visit_parameter_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
ty: Index,
|
||||
name: intern::Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
_ = (idx, name);
|
||||
self.visit_any(ast, ty)
|
||||
}
|
||||
|
||||
fn visit_array_type_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
length: Index,
|
||||
pointer: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
_ = self.visit_any(ast, length)?;
|
||||
let pointee = self.visit_any(ast, pointer)?.expect("no type?");
|
||||
|
||||
variant!(self.ip.get_key(pointee) => intern::Key::PointerType { pointee, flags });
|
||||
|
||||
// get interened value from constant node
|
||||
let length = {
|
||||
let value = ast.datas[length].as_index_intern().1;
|
||||
|
||||
match self.ip.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.ip.get_array_type(pointee, Some(flags), length);
|
||||
ast.tags[idx] = Tag::InternedType;
|
||||
ast.datas[idx] = Data::intern(ty);
|
||||
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
fn visit_pointer_type_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
ty: Index,
|
||||
flags: intern::PointerFlags,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let pointee = self.visit_any(ast, ty)?.expect("no type?");
|
||||
|
||||
let ty = self.ip.get_pointer_type(pointee, Some(flags));
|
||||
|
||||
ast.tags[idx] = Tag::InternedType;
|
||||
ast.datas[idx] = Data::intern(ty);
|
||||
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
fn visit_type_decl_ref_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
decl: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let ty = self.visit_any(ast, decl)?.expect("no type?");
|
||||
|
||||
ast.tags[idx] = Tag::InternedType;
|
||||
ast.datas[idx] = Data::intern(ty);
|
||||
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
fn visit_function_proto_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
name: intern::Index,
|
||||
return_type: Index,
|
||||
parameter_list: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
variant!(ast.get_ast_node(parameter_list) => AstNode::ParameterList { params });
|
||||
|
||||
let return_type = self.visit_any(ast, return_type)?.expect("no type?");
|
||||
|
||||
let params = params
|
||||
.into_iter()
|
||||
.map(|param| self.visit_parameter(ast, param).map(|a| a.unwrap()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let ty = self.ip.get_function_type(return_type, params);
|
||||
|
||||
ast.tags[idx] = Tag::FunctionProtoInterned;
|
||||
ast.datas[idx] = Data::two_interns(name, ty);
|
||||
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
fn visit_function_proto_interned_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
name: intern::Index,
|
||||
ty: intern::Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
fn visit_struct_decl_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
name: intern::Index,
|
||||
flags: intern::StructFlags,
|
||||
field_names: Vec<intern::Index>,
|
||||
field_types: Vec<Index>,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let types = field_types
|
||||
.into_iter()
|
||||
.map(|i| self.visit_any(ast, i).map(Option::unwrap))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let ty = self.ip.insert_or_replace_struct_type(
|
||||
name,
|
||||
idx,
|
||||
flags.packed,
|
||||
flags.c_like,
|
||||
field_names.into_iter().zip(types),
|
||||
);
|
||||
|
||||
ast.tags[idx] = Tag::StructDeclInterned;
|
||||
ast.datas[idx] = Data::two_interns(name, ty);
|
||||
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
fn visit_function_decl_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
proto: Index,
|
||||
body: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let ty = self.visit_any(ast, proto)?.expect("no type?");
|
||||
let body = self.visit_block(ast, body)?.unwrap_or(intern::Index::VOID);
|
||||
|
||||
let ret_ty = self.ip.try_get_return_type(ty).expect("no type?");
|
||||
|
||||
if body != ret_ty {
|
||||
self.errors.push(Error {
|
||||
idx,
|
||||
kind: ErrorKind::MismatchingTypes,
|
||||
});
|
||||
Ok(Some(intern::Index::VOID))
|
||||
} else {
|
||||
Ok(Some(ty))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_block_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
statements: Vec<Index>,
|
||||
expr: Option<Index>,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
for stmt in statements {
|
||||
self.visit_any(ast, stmt)?;
|
||||
}
|
||||
|
||||
expr.map(|expr| self.visit_any(ast, expr))
|
||||
.transpose()
|
||||
.map(Option::flatten)
|
||||
}
|
||||
|
||||
fn visit_file_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
decls: Vec<Index>,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
for decl in decls {
|
||||
self.visit_any(ast, decl)?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn visit_struct_decl_interned_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
name: intern::Index,
|
||||
ty: intern::Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
fn visit_interned_type_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
intern: intern::Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
Ok(Some(intern))
|
||||
}
|
||||
|
||||
fn visit_any(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: super::Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let (tag, data) = ast.get_node_tag_and_data(idx);
|
||||
|
||||
let _ty = match tag {
|
||||
Tag::Root => unreachable!(),
|
||||
Tag::InternedType => Some(data.as_intern()),
|
||||
Tag::File => self.visit_file(ast, idx)?,
|
||||
Tag::ArrayType => self.visit_array_type(ast, idx)?,
|
||||
Tag::PointerType => self.visit_pointer_type(ast, idx)?,
|
||||
Tag::TypeDeclRef => self.visit_type_decl_ref(ast, idx)?,
|
||||
Tag::FunctionProtoInterned => self.visit_function_proto_interned(ast, idx)?,
|
||||
Tag::FunctionProto => self.visit_function_proto(ast, idx)?,
|
||||
Tag::Parameter => self.visit_parameter(ast, idx)?,
|
||||
Tag::StructDecl => self.visit_struct_decl(ast, idx)?,
|
||||
Tag::StructDeclInterned => self.visit_struct_decl_interned(ast, idx)?,
|
||||
Tag::FunctionDecl => self.visit_function_decl(ast, idx)?,
|
||||
Tag::ParameterList => todo!(),
|
||||
Tag::Block | Tag::BlockTrailingExpr => self.visit_block(ast, idx)?,
|
||||
Tag::Constant => self.visit_constant(ast, idx)?,
|
||||
Tag::ExprStmt => self.visit_expr_stmt(ast, idx)?,
|
||||
Tag::ReturnStmt => self.visit_return_stmt(ast, idx)?,
|
||||
Tag::ReturnExprStmt => todo!(),
|
||||
Tag::VarDecl => todo!(),
|
||||
Tag::MutVarDecl => todo!(),
|
||||
Tag::VarDeclAssignment => todo!(),
|
||||
Tag::MutVarDeclAssignment => todo!(),
|
||||
Tag::GlobalDecl => todo!(),
|
||||
Tag::FieldDecl => todo!(),
|
||||
Tag::DeclRef => todo!(),
|
||||
Tag::DeclRefUnresolved => todo!(),
|
||||
Tag::TypeDeclRefUnresolved => todo!(),
|
||||
Tag::CallExpr => todo!(),
|
||||
Tag::FieldAccess => todo!(),
|
||||
Tag::ArgumentList => todo!(),
|
||||
Tag::Argument => todo!(),
|
||||
Tag::NamedArgument => todo!(),
|
||||
Tag::ExplicitCast => self.visit_explicit_cast(ast, idx)?,
|
||||
Tag::Deref => self.visit_deref(ast, idx)?,
|
||||
Tag::AddressOf => self.visit_address_of(ast, idx)?,
|
||||
Tag::Not | Tag::Negate => {
|
||||
let ty = self.visit_any(ast, data.as_index())?;
|
||||
ty
|
||||
}
|
||||
Tag::PlaceToValueConversion => self.visit_place_to_value_conversion(ast, idx)?,
|
||||
Tag::ValueToPlaceConversion => self.visit_value_to_place_conversion(ast, idx)?,
|
||||
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 => {
|
||||
let (lhs, rhs) = data.as_two_indices();
|
||||
let lhs = self.visit_any(ast, lhs)?.unwrap();
|
||||
let rhs = self.visit_any(ast, rhs)?.unwrap();
|
||||
|
||||
if lhs != rhs {
|
||||
self.errors.push(Error {
|
||||
idx,
|
||||
kind: ErrorKind::MismatchingTypes,
|
||||
});
|
||||
}
|
||||
|
||||
Some(lhs)
|
||||
}
|
||||
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::Error => todo!(),
|
||||
Tag::Undefined => todo!(),
|
||||
};
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn visit_explicit_cast_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
expr: Index,
|
||||
ty: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
_ = self.visit_any(ast, expr)?;
|
||||
// TODO: make sure this cast is legal
|
||||
let ty = self.visit_any(ast, ty)?;
|
||||
|
||||
Ok(ty)
|
||||
}
|
||||
|
||||
fn visit_address_of_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
expr: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
self.visit_any(ast, expr)
|
||||
}
|
||||
|
||||
fn visit_deref_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
expr: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let ty = self.visit_any(ast, expr)?.unwrap();
|
||||
if let intern::Key::PointerType { pointee, .. } = self.ip.get_key(ty) {
|
||||
Ok(Some(pointee))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_place_to_value_conversion_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
expr: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let ty = self.visit_any(ast, expr)?;
|
||||
|
||||
if let Some(ty) = ty {
|
||||
Ok(self.ip.try_get_pointee_type(ty))
|
||||
} else {
|
||||
self.errors.push(Error {
|
||||
idx,
|
||||
kind: ErrorKind::DerefNonPointer,
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_value_to_place_conversion_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
expr: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let ty = self.visit_any(ast, expr)?;
|
||||
|
||||
if let Some(ty) = ty {
|
||||
Ok(Some(self.ip.get_pointer_type(ty, None)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_if_else_expr_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
cond: Index,
|
||||
a: Index,
|
||||
b: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
self.visit_any(ast, cond)?;
|
||||
let a = self.visit_block(ast, a)?;
|
||||
let b = self.visit_block(ast, b)?;
|
||||
|
||||
if a != b {
|
||||
self.errors.push(Error {
|
||||
idx,
|
||||
kind: ErrorKind::MismatchingTypes,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn visit_if_expr_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
cond: Index,
|
||||
body: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
self.visit_any(ast, cond)?;
|
||||
self.visit_block(ast, body)?;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn visit_subscript_expr_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
lhs: Index,
|
||||
index: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let lhs = self.visit_any(ast, lhs)?.unwrap();
|
||||
let index = self.visit_any(ast, index)?.unwrap();
|
||||
|
||||
if index != intern::Index::USIZE {
|
||||
self.errors.push(Error {
|
||||
idx,
|
||||
kind: ErrorKind::MismatchingTypes,
|
||||
});
|
||||
}
|
||||
|
||||
let pointee = self.ip.try_get_pointee_type(lhs).unwrap();
|
||||
let pointer = self.ip.get_pointer_type(pointee, None);
|
||||
|
||||
Ok(Some(pointer))
|
||||
}
|
||||
|
||||
fn visit_assign_impl(
|
||||
&mut self,
|
||||
ast: &'a mut Ast,
|
||||
idx: Index,
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
) -> Result<Self::Value, Self::Error> {
|
||||
let lhs = self.visit_any(ast, lhs)?.unwrap();
|
||||
let rhs = self.visit_any(ast, rhs)?.unwrap();
|
||||
|
||||
if self.ip.try_get_pointee_type(lhs) != Some(rhs) {
|
||||
self.errors.push(Error {
|
||||
idx,
|
||||
kind: ErrorKind::MismatchingTypes,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
625
src/ast2/visitor.rs
Normal file
625
src/ast2/visitor.rs
Normal file
|
@ -0,0 +1,625 @@
|
|||
use crate::{ast2::tag::AstNode, variant};
|
||||
|
||||
use super::{tag::AstNodeExt, *};
|
||||
|
||||
pub trait AstExt {
|
||||
fn get_node_children(&self, node: Index) -> Vec<Index>;
|
||||
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data);
|
||||
|
||||
fn get_node_data_for_tag(&self, idx: Index, tag: Tag) -> Option<Data> {
|
||||
let (t, data) = self.get_node_tag_and_data(idx);
|
||||
if t == tag {
|
||||
Some(data)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
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:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tag_visit_fn {
|
||||
($($tag:tt {$($field_name:ident : $field_ty:ty),* $(,)?}),* $(,)?) => {
|
||||
$(
|
||||
paste::paste! {
|
||||
|
||||
fn [<visit_ $tag:snake>](&mut self, ast: Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
||||
variant!(ast.get_ast_node(idx) => AstNode::$tag { $($field_name),* });
|
||||
self.[<visit_ $tag:snake _impl>](ast, idx, $($field_name),*)
|
||||
}
|
||||
fn [<visit_ $tag:snake _impl>](&mut self, ast: Ast, idx: Index, $($field_name: $field_ty),*) -> Result<Self::Value, Self::Error> {
|
||||
_ = (ast, idx, $($field_name),*);
|
||||
Err(Self::UNIMPL)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
use intern::Index as Interned;
|
||||
|
||||
pub trait AstVisitorTrait<Ast: AstExt + AstNodeExt> {
|
||||
type Error;
|
||||
type Value;
|
||||
const UNIMPL: Self::Error;
|
||||
|
||||
tag_visit_fn!(
|
||||
File {
|
||||
decls: Vec<Index>,
|
||||
},
|
||||
FunctionProto {
|
||||
name: Interned,
|
||||
return_type: Index,
|
||||
parameter_list: Index,
|
||||
},
|
||||
FunctionProtoInterned {
|
||||
name: Interned,
|
||||
ty: Interned,
|
||||
},
|
||||
FunctionDecl {
|
||||
proto: Index,
|
||||
body: Index,
|
||||
},
|
||||
ParameterList {
|
||||
params: Vec<Index>,
|
||||
},
|
||||
Parameter {
|
||||
ty: Index,
|
||||
name: Interned,
|
||||
},
|
||||
Block {
|
||||
statements: Vec<Index>,
|
||||
expr: Option<Index>,
|
||||
},
|
||||
Constant {
|
||||
ty: Index,
|
||||
value: Interned,
|
||||
},
|
||||
ExprStmt {
|
||||
expr: Index,
|
||||
},
|
||||
ReturnStmt {},
|
||||
ReturnExprStmt {
|
||||
expr: Index,
|
||||
},
|
||||
VarDecl {
|
||||
name: Interned,
|
||||
ty: Index,
|
||||
},
|
||||
MutVarDecl {
|
||||
name: Interned,
|
||||
ty: Index,
|
||||
},
|
||||
VarDeclAssignment {
|
||||
name: Interned,
|
||||
expr: Index,
|
||||
ty: Option<Index>,
|
||||
},
|
||||
MutVarDeclAssignment {
|
||||
name: Interned,
|
||||
expr: Index,
|
||||
ty: Option<Index>,
|
||||
},
|
||||
GlobalDecl {
|
||||
name: Interned,
|
||||
expr: Index,
|
||||
ty: Index,
|
||||
},
|
||||
StructDecl {
|
||||
name: Interned,
|
||||
flags: StructFlags,
|
||||
field_names: Vec<Interned>,
|
||||
field_types: Vec<Index>,
|
||||
},
|
||||
StructDeclInterned {
|
||||
name: Interned,
|
||||
ty: Interned,
|
||||
},
|
||||
FieldDecl {
|
||||
name: Interned,
|
||||
ty: Index,
|
||||
},
|
||||
DeclRef {
|
||||
decl: Index,
|
||||
},
|
||||
DeclRefUnresolved {
|
||||
scope: Index,
|
||||
name: Interned,
|
||||
},
|
||||
InternedType {
|
||||
intern: Interned,
|
||||
},
|
||||
TypeDeclRef {
|
||||
decl: Index,
|
||||
},
|
||||
TypeDeclRefUnresolved {
|
||||
scope: Index,
|
||||
name: Interned,
|
||||
},
|
||||
PointerType {
|
||||
ty: Index,
|
||||
flags: PointerFlags,
|
||||
},
|
||||
ArrayType {
|
||||
length: Index,
|
||||
pointer: Index,
|
||||
},
|
||||
CallExpr {
|
||||
func: Index,
|
||||
argument_list: Index,
|
||||
},
|
||||
FieldAccess {
|
||||
field_name: Interned,
|
||||
expr: Index,
|
||||
},
|
||||
ArgumentList {
|
||||
arguments: Vec<Index>,
|
||||
},
|
||||
Argument {
|
||||
expr: Index,
|
||||
name: Option<Interned>,
|
||||
},
|
||||
ExplicitCast {
|
||||
expr: Index,
|
||||
ty: Index,
|
||||
},
|
||||
Deref {
|
||||
expr: Index,
|
||||
},
|
||||
AddressOf {
|
||||
expr: Index,
|
||||
},
|
||||
Not {
|
||||
expr: Index,
|
||||
},
|
||||
Negate {
|
||||
expr: Index,
|
||||
},
|
||||
PlaceToValueConversion {
|
||||
expr: Index,
|
||||
},
|
||||
ValueToPlaceConversion {
|
||||
expr: Index,
|
||||
},
|
||||
Or {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
And {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
BitOr {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
BitXOr {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
BitAnd {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Eq {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
NEq {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Lt {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Gt {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Le {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Ge {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Shl {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Shr {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Add {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Sub {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Mul {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Div {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Rem {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
Assign {
|
||||
lhs: Index,
|
||||
rhs: Index,
|
||||
},
|
||||
SubscriptExpr {
|
||||
lhs: Index,
|
||||
index: Index,
|
||||
},
|
||||
IfExpr {
|
||||
cond: Index,
|
||||
body: Index,
|
||||
},
|
||||
IfElseExpr {
|
||||
cond: Index,
|
||||
a: Index,
|
||||
b: Index,
|
||||
},
|
||||
Error {
|
||||
err: ParseError,
|
||||
},
|
||||
Undefined {},
|
||||
);
|
||||
|
||||
fn visit_any(&mut self, ast: Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
||||
match ast.get_ast_node(idx) {
|
||||
AstNode::File { decls } => self.visit_file_impl(ast, idx, decls),
|
||||
AstNode::FunctionProto {
|
||||
name,
|
||||
return_type,
|
||||
parameter_list,
|
||||
} => self.visit_function_proto_impl(ast, idx, name, return_type, parameter_list),
|
||||
AstNode::FunctionProtoInterned { name, ty } => {
|
||||
self.visit_function_proto_interned_impl(ast, idx, name, ty)
|
||||
}
|
||||
AstNode::FunctionDecl { proto, body } => {
|
||||
self.visit_function_decl_impl(ast, idx, proto, body)
|
||||
}
|
||||
AstNode::ParameterList { params } => self.visit_parameter_list_impl(ast, idx, params),
|
||||
AstNode::Parameter { ty, name } => self.visit_parameter_impl(ast, idx, ty, name),
|
||||
AstNode::Block { statements, expr } => {
|
||||
self.visit_block_impl(ast, idx, statements, expr)
|
||||
}
|
||||
AstNode::Constant { ty, value } => self.visit_constant_impl(ast, idx, ty, value),
|
||||
AstNode::ExprStmt { expr } => self.visit_expr_stmt_impl(ast, idx, expr),
|
||||
AstNode::ReturnStmt => self.visit_return_stmt_impl(ast, idx),
|
||||
AstNode::ReturnExprStmt { expr } => self.visit_return_expr_stmt_impl(ast, idx, expr),
|
||||
AstNode::VarDecl { name, ty } => self.visit_var_decl_impl(ast, idx, name, ty),
|
||||
AstNode::MutVarDecl { name, ty } => self.visit_mut_var_decl_impl(ast, idx, name, ty),
|
||||
AstNode::VarDeclAssignment { name, expr, ty } => {
|
||||
self.visit_var_decl_assignment_impl(ast, idx, name, expr, ty)
|
||||
}
|
||||
AstNode::MutVarDeclAssignment { name, expr, ty } => {
|
||||
self.visit_mut_var_decl_assignment_impl(ast, idx, name, expr, ty)
|
||||
}
|
||||
AstNode::GlobalDecl { name, expr, ty } => {
|
||||
self.visit_global_decl_impl(ast, idx, name, expr, ty)
|
||||
}
|
||||
AstNode::StructDecl {
|
||||
name,
|
||||
flags,
|
||||
field_names,
|
||||
field_types,
|
||||
} => self.visit_struct_decl_impl(ast, idx, name, flags, field_names, field_types),
|
||||
AstNode::StructDeclInterned { name, ty } => {
|
||||
self.visit_struct_decl_interned_impl(ast, idx, name, ty)
|
||||
}
|
||||
AstNode::FieldDecl { name, ty } => self.visit_field_decl_impl(ast, idx, name, ty),
|
||||
AstNode::DeclRef { decl } => self.visit_decl_ref_impl(ast, idx, decl),
|
||||
AstNode::DeclRefUnresolved { scope, name } => {
|
||||
self.visit_decl_ref_unresolved_impl(ast, idx, scope, name)
|
||||
}
|
||||
AstNode::InternedType { intern } => self.visit_interned_type_impl(ast, idx, intern),
|
||||
AstNode::TypeDeclRef { decl } => self.visit_type_decl_ref_impl(ast, idx, decl),
|
||||
AstNode::TypeDeclRefUnresolved { scope, name } => {
|
||||
self.visit_type_decl_ref_unresolved_impl(ast, idx, scope, name)
|
||||
}
|
||||
AstNode::PointerType { ty, flags } => self.visit_pointer_type_impl(ast, idx, ty, flags),
|
||||
AstNode::ArrayType { length, pointer } => {
|
||||
self.visit_array_type_impl(ast, idx, length, pointer)
|
||||
}
|
||||
AstNode::CallExpr {
|
||||
func,
|
||||
argument_list,
|
||||
} => self.visit_call_expr_impl(ast, idx, func, argument_list),
|
||||
AstNode::FieldAccess { field_name, expr } => {
|
||||
self.visit_field_access_impl(ast, idx, field_name, expr)
|
||||
}
|
||||
AstNode::ArgumentList { arguments } => {
|
||||
self.visit_argument_list_impl(ast, idx, arguments)
|
||||
}
|
||||
AstNode::Argument { expr, name } => self.visit_argument_impl(ast, idx, expr, name),
|
||||
AstNode::ExplicitCast { expr, ty } => self.visit_explicit_cast_impl(ast, idx, expr, ty),
|
||||
AstNode::Deref { expr } => self.visit_deref_impl(ast, idx, expr),
|
||||
AstNode::AddressOf { expr } => self.visit_address_of_impl(ast, idx, expr),
|
||||
AstNode::Not { expr } => self.visit_not_impl(ast, idx, expr),
|
||||
AstNode::Negate { expr } => self.visit_negate_impl(ast, idx, expr),
|
||||
AstNode::PlaceToValueConversion { expr } => {
|
||||
self.visit_place_to_value_conversion_impl(ast, idx, expr)
|
||||
}
|
||||
AstNode::ValueToPlaceConversion { expr } => {
|
||||
self.visit_value_to_place_conversion_impl(ast, idx, expr)
|
||||
}
|
||||
AstNode::Or { lhs, rhs } => self.visit_or_impl(ast, idx, lhs, rhs),
|
||||
AstNode::And { lhs, rhs } => self.visit_and_impl(ast, idx, lhs, rhs),
|
||||
AstNode::BitOr { lhs, rhs } => self.visit_bit_or_impl(ast, idx, lhs, rhs),
|
||||
AstNode::BitXOr { lhs, rhs } => self.visit_bit_x_or_impl(ast, idx, lhs, rhs),
|
||||
AstNode::BitAnd { lhs, rhs } => self.visit_bit_and_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Eq { lhs, rhs } => self.visit_eq_impl(ast, idx, lhs, rhs),
|
||||
AstNode::NEq { lhs, rhs } => self.visit_n_eq_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Lt { lhs, rhs } => self.visit_lt_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Gt { lhs, rhs } => self.visit_gt_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Le { lhs, rhs } => self.visit_le_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Ge { lhs, rhs } => self.visit_ge_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Shl { lhs, rhs } => self.visit_shl_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Shr { lhs, rhs } => self.visit_shr_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Add { lhs, rhs } => self.visit_add_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Sub { lhs, rhs } => self.visit_sub_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Mul { lhs, rhs } => self.visit_mul_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Div { lhs, rhs } => self.visit_div_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Rem { lhs, rhs } => self.visit_rem_impl(ast, idx, lhs, rhs),
|
||||
AstNode::Assign { lhs, rhs } => self.visit_assign_impl(ast, idx, lhs, rhs),
|
||||
AstNode::SubscriptExpr { lhs, index: rhs } => {
|
||||
self.visit_subscript_expr_impl(ast, idx, lhs, rhs)
|
||||
}
|
||||
AstNode::IfExpr { cond, body } => self.visit_if_expr_impl(ast, idx, cond, body),
|
||||
AstNode::IfElseExpr { cond, a, b } => {
|
||||
self.visit_if_else_expr_impl(ast, idx, cond, a, b)
|
||||
}
|
||||
AstNode::Error { err } => self.visit_error_impl(ast, idx, err),
|
||||
AstNode::Undefined => self.visit_undefined_impl(ast, idx),
|
||||
AstNode::Root { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,7 +55,7 @@ fn main() {
|
|||
println!("AST:\n{buf}");
|
||||
}
|
||||
"ast2" => {
|
||||
let mut tree2 = compiler::ast2::ast_gen::Parser::new();
|
||||
let mut tree2 = compiler::ast2::parser::Parser::new();
|
||||
tree2.parse(tokens.iter());
|
||||
eprintln!("{tree2:#?}");
|
||||
println!("AST (new):\n{tree2}");
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#![feature(
|
||||
extract_if,
|
||||
iter_advance_by,
|
||||
box_into_inner,
|
||||
hash_extract_if,
|
||||
bigint_helper_methods,
|
||||
map_try_insert,
|
||||
iter_intersperse,
|
||||
|
@ -29,6 +27,9 @@ pub mod symbol_table;
|
|||
pub mod tokens;
|
||||
pub mod triples;
|
||||
|
||||
pub mod utils;
|
||||
use utils::unit;
|
||||
|
||||
pub fn tokenize<'a>(
|
||||
bytes: &'a [u8],
|
||||
) -> Result<lexer::Tokenizer<'a>, (lexer::Tokenizer<'a>, Vec<lexer::TokenizeError>)> {
|
||||
|
|
|
@ -35,25 +35,13 @@ impl SymbolPath {
|
|||
for node in self.0.iter().skip(1).rev() {
|
||||
match tree.nodes.get_node(node.unwrap()) {
|
||||
Tag::VarDecl { name, .. } => {
|
||||
_ = write!(
|
||||
&mut buf,
|
||||
"V{}::",
|
||||
tree.get_ident_str(*name).unwrap()
|
||||
);
|
||||
_ = write!(&mut buf, "V{}::", tree.get_ident_str(*name).unwrap());
|
||||
}
|
||||
Tag::GlobalDecl { name, .. } => {
|
||||
_ = write!(
|
||||
&mut buf,
|
||||
"G{}::",
|
||||
tree.get_ident_str(*name).unwrap()
|
||||
);
|
||||
_ = write!(&mut buf, "G{}::", tree.get_ident_str(*name).unwrap());
|
||||
}
|
||||
Tag::FunctionProto { name, .. } => {
|
||||
_ = write!(
|
||||
&mut buf,
|
||||
"F{}::",
|
||||
tree.get_ident_str(*name).unwrap()
|
||||
);
|
||||
_ = write!(&mut buf, "F{}::", tree.get_ident_str(*name).unwrap());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -142,12 +130,7 @@ impl Drop for InnerSymbolTable {
|
|||
}
|
||||
|
||||
impl InnerSymbolTable {
|
||||
fn insert_symbol(
|
||||
&mut self,
|
||||
name: &str,
|
||||
node: AstNode,
|
||||
kind: SymbolKind,
|
||||
) -> &SymbolRecord {
|
||||
fn insert_symbol(&mut self, name: &str, node: AstNode, kind: SymbolKind) -> &SymbolRecord {
|
||||
match kind {
|
||||
SymbolKind::Var => {
|
||||
self.ordered_identifiers.push(SymbolRecord {
|
||||
|
@ -160,11 +143,7 @@ impl InnerSymbolTable {
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_orderless_symbol(
|
||||
&mut self,
|
||||
name: &str,
|
||||
node: AstNode,
|
||||
) -> &SymbolRecord {
|
||||
fn insert_orderless_symbol(&mut self, name: &str, node: AstNode) -> &SymbolRecord {
|
||||
self.orderless_identifiers.insert(
|
||||
name.to_owned(),
|
||||
SymbolRecord {
|
||||
|
@ -175,11 +154,7 @@ impl InnerSymbolTable {
|
|||
self.orderless_identifiers.get(name).unwrap()
|
||||
}
|
||||
|
||||
fn find_symbol_or_insert_with<'a, F>(
|
||||
&'a mut self,
|
||||
name: &str,
|
||||
cb: F,
|
||||
) -> &'a SymbolRecord
|
||||
fn find_symbol_or_insert_with<'a, F>(&'a mut self, name: &str, cb: F) -> &'a SymbolRecord
|
||||
where
|
||||
F: FnOnce() -> (AstNode, SymbolKind),
|
||||
{
|
||||
|
@ -202,9 +177,7 @@ impl InnerSymbolTable {
|
|||
.find(|(_, v)| v.decl == decl)
|
||||
.map(|(_, v)| v)
|
||||
})
|
||||
.or_else(|| {
|
||||
self.parent_ref().and_then(|p| p.find_symbol_by_decl(decl))
|
||||
})
|
||||
.or_else(|| self.parent_ref().and_then(|p| p.find_symbol_by_decl(decl)))
|
||||
}
|
||||
|
||||
fn find_any_symbol(&self, name: &str) -> Option<&SymbolRecord> {
|
||||
|
@ -219,9 +192,7 @@ impl InnerSymbolTable {
|
|||
self.ordered_identifiers
|
||||
.iter()
|
||||
.find(|r| r.name.as_str() == name)
|
||||
.or_else(|| {
|
||||
self.parent_ref().and_then(|p| p.find_ordered_symbol(name))
|
||||
})
|
||||
.or_else(|| self.parent_ref().and_then(|p| p.find_ordered_symbol(name)))
|
||||
}
|
||||
|
||||
fn find_orderless_symbol(&self, name: &str) -> Option<&SymbolRecord> {
|
||||
|
@ -315,12 +286,7 @@ impl SymbolTableWrapper {
|
|||
}
|
||||
|
||||
impl SymbolTableWrapper {
|
||||
pub fn insert_symbol(
|
||||
&mut self,
|
||||
name: &str,
|
||||
node: AstNode,
|
||||
kind: SymbolKind,
|
||||
) -> &SymbolRecord {
|
||||
pub fn insert_symbol(&mut self, name: &str, node: AstNode, kind: SymbolKind) -> &SymbolRecord {
|
||||
self.current_mut().insert_symbol(name, node, kind)
|
||||
}
|
||||
|
||||
|
@ -328,27 +294,15 @@ impl SymbolTableWrapper {
|
|||
self.root_mut().find_orderless_symbol(name)
|
||||
}
|
||||
|
||||
pub fn insert_root_symbol(
|
||||
&mut self,
|
||||
name: &str,
|
||||
node: AstNode,
|
||||
) -> &SymbolRecord {
|
||||
pub fn insert_root_symbol(&mut self, name: &str, node: AstNode) -> &SymbolRecord {
|
||||
self.root_mut().insert_orderless_symbol(name, node)
|
||||
}
|
||||
|
||||
pub fn insert_orderless_symbol(
|
||||
&mut self,
|
||||
name: &str,
|
||||
node: AstNode,
|
||||
) -> &SymbolRecord {
|
||||
pub fn insert_orderless_symbol(&mut self, name: &str, node: AstNode) -> &SymbolRecord {
|
||||
self.current_mut().insert_orderless_symbol(name, node)
|
||||
}
|
||||
|
||||
pub fn find_symbol_or_insert_with<'a, F>(
|
||||
&'a mut self,
|
||||
name: &str,
|
||||
cb: F,
|
||||
) -> &'a SymbolRecord
|
||||
pub fn find_symbol_or_insert_with<'a, F>(&'a mut self, name: &str, cb: F) -> &'a SymbolRecord
|
||||
where
|
||||
F: FnOnce() -> (AstNode, SymbolKind),
|
||||
{
|
||||
|
@ -470,6 +424,40 @@ pub mod syms2 {
|
|||
},
|
||||
}
|
||||
|
||||
impl Key {
|
||||
pub fn kind(&self) -> Option<SymbolKind> {
|
||||
match self {
|
||||
Key::Symbol { kind, .. } => Some(*kind),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum DeclKind {
|
||||
Local = 1,
|
||||
Parameter,
|
||||
}
|
||||
|
||||
impl DeclKind {
|
||||
pub fn from_u32(v: u32) -> Option<Self> {
|
||||
match v {
|
||||
1 => Some(Self::Local),
|
||||
2 => Some(Self::Parameter),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<SymbolKind> for Option<DeclKind> {
|
||||
fn from(value: SymbolKind) -> Self {
|
||||
match value {
|
||||
SymbolKind::Parameter(_) => Some(DeclKind::Parameter),
|
||||
SymbolKind::Local(_) => Some(DeclKind::Local),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum SymbolKind {
|
||||
__First,
|
||||
|
@ -479,6 +467,7 @@ pub mod syms2 {
|
|||
__TypeScope,
|
||||
Scope,
|
||||
ParentScope,
|
||||
Parameter(SourceLocation),
|
||||
Local(SourceLocation),
|
||||
__Last,
|
||||
}
|
||||
|
@ -526,9 +515,7 @@ pub mod syms2 {
|
|||
}
|
||||
let entries = self.inner.iter().map(|(key, val)| {
|
||||
let payload = match key {
|
||||
Key::ScopeByIndex { .. } => {
|
||||
ExpandedPayload::Intern(val.as_intern())
|
||||
}
|
||||
Key::ScopeByIndex { .. } => ExpandedPayload::Intern(val.as_intern()),
|
||||
_ => ExpandedPayload::Ast(val.as_ast()),
|
||||
};
|
||||
|
||||
|
@ -567,7 +554,7 @@ pub mod syms2 {
|
|||
scope: AstIndex,
|
||||
name: InternIndex,
|
||||
loc: SourceLocation,
|
||||
) -> Option<AstIndex> {
|
||||
) -> Option<(Key, AstIndex)> {
|
||||
use SymbolKind::*;
|
||||
let range = self.inner.range(
|
||||
Key::Symbol {
|
||||
|
@ -581,8 +568,8 @@ pub mod syms2 {
|
|||
},
|
||||
);
|
||||
|
||||
if let Some((_, payload)) = range.rev().next() {
|
||||
Some(payload.as_ast())
|
||||
if let Some((key, payload)) = range.rev().next() {
|
||||
Some((*key, payload.as_ast()))
|
||||
} else {
|
||||
if let Some(parent) = self.inner.get(&Key::Symbol {
|
||||
scope,
|
||||
|
@ -601,7 +588,7 @@ pub mod syms2 {
|
|||
scope: AstIndex,
|
||||
name: InternIndex,
|
||||
loc: SourceLocation,
|
||||
) -> Option<AstIndex> {
|
||||
) -> Option<(Key, AstIndex)> {
|
||||
use SymbolKind::*;
|
||||
let range = self.inner.range(
|
||||
Key::Symbol {
|
||||
|
@ -615,15 +602,15 @@ pub mod syms2 {
|
|||
},
|
||||
);
|
||||
|
||||
if let Some((_, payload)) = range.rev().next() {
|
||||
Some(payload.as_ast())
|
||||
if let Some((key, payload)) = range.rev().next() {
|
||||
Some((*key, payload.as_ast()))
|
||||
} else {
|
||||
if let Some(parent) = self.inner.get(&Key::Symbol {
|
||||
scope,
|
||||
name: InternIndex::invalid(),
|
||||
kind: ParentScope,
|
||||
}) {
|
||||
self.find_symbol(parent.as_ast(), name, loc)
|
||||
self.find_type_symbol(parent.as_ast(), name, loc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -637,10 +624,8 @@ pub mod syms2 {
|
|||
kind: SymbolKind,
|
||||
ast: AstIndex,
|
||||
) {
|
||||
self.inner.insert(
|
||||
Key::Symbol { scope, name, kind },
|
||||
Payload::new_ast(ast),
|
||||
);
|
||||
self.inner
|
||||
.insert(Key::Symbol { scope, name, kind }, Payload::new_ast(ast));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,10 +159,13 @@ pub enum Inst {
|
|||
Constant,
|
||||
/// size, align
|
||||
Alloca,
|
||||
/// (pointee type)
|
||||
/// src
|
||||
Load(intern::Index),
|
||||
/// (pointee type)
|
||||
/// src, dst
|
||||
Store(intern::Index),
|
||||
/// (pointer type)
|
||||
/// ptr, index,
|
||||
GetElementPtr(intern::Index),
|
||||
/// size, align
|
||||
|
@ -759,8 +762,8 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
}
|
||||
|
||||
pub struct IR {
|
||||
nodes: Vec<Inst>,
|
||||
data: Vec<Option<Data>>,
|
||||
pub(crate) nodes: Vec<Inst>,
|
||||
pub(crate) data: Vec<Option<Data>>,
|
||||
// intern_pool: &'a mut InternPool,
|
||||
}
|
||||
|
||||
|
|
25
src/utils.rs
Normal file
25
src/utils.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use core::{cell::UnsafeCell, mem::ManuallyDrop};
|
||||
|
||||
pub fn unit<T>(_: T) {}
|
||||
|
||||
pub struct DropGuard<F: FnOnce()>(UnsafeCell<ManuallyDrop<F>>);
|
||||
|
||||
impl<F> DropGuard<F>
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
pub fn new(f: F) -> DropGuard<F> {
|
||||
Self(UnsafeCell::new(ManuallyDrop::new(f)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Drop for DropGuard<F>
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ManuallyDrop::take(&mut *self.0.get())();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue