not really sure, i guess this is an IR?
This commit is contained in:
		
							parent
							
								
									02be9bdc26
								
							
						
					
					
						commit
						c3157b1355
					
				
							
								
								
									
										139
									
								
								src/ast.rs
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								src/ast.rs
									
									
									
									
									
								
							|  | @ -186,30 +186,30 @@ pub enum LetOrVar { | ||||||
|     Var, |     Var, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||||
| pub struct IntegralType { | pub struct IntegralType { | ||||||
|     pub signed: bool, |     pub signed: bool, | ||||||
|     pub bits: u16, |     pub bits: u16, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ToString for IntegralType { | impl core::fmt::Display for IntegralType { | ||||||
|     fn to_string(&self) -> String { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         format!("{}{}", if self.signed { "i" } else { "u" }, self.bits) |         write!(f, "{}{}", if self.signed { "i" } else { "u" }, self.bits) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||||
| pub enum FloatingType { | pub enum FloatingType { | ||||||
|     Binary32, |     Binary32, | ||||||
|     Binary64, |     Binary64, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ToString for FloatingType { | impl core::fmt::Display for FloatingType { | ||||||
|     fn to_string(&self) -> String { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         match self { |         f.write_str(match self { | ||||||
|             FloatingType::Binary32 => "binary32".to_owned(), |             FloatingType::Binary32 => "binary32", | ||||||
|             FloatingType::Binary64 => "binary64".to_owned(), |             FloatingType::Binary64 => "binary64", | ||||||
|         } |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -222,6 +222,123 @@ impl IntegralType { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||||
|  | pub enum Type { | ||||||
|  |     Any, | ||||||
|  |     Void, | ||||||
|  |     Bool, | ||||||
|  |     Integer(IntegralType), | ||||||
|  |     Floating(FloatingType), | ||||||
|  |     Pointer { | ||||||
|  |         constness: bool, | ||||||
|  |         pointee: Box<Self>, | ||||||
|  |     }, | ||||||
|  |     Fn { | ||||||
|  |         parameter_types: Vec<Self>, | ||||||
|  |         return_type: Box<Self>, | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Type { | ||||||
|  |     pub fn void() -> Type { | ||||||
|  |         Self::Void | ||||||
|  |     } | ||||||
|  |     pub fn bool() -> Type { | ||||||
|  |         Self::Void | ||||||
|  |     } | ||||||
|  |     pub fn any() -> Type { | ||||||
|  |         Self::Void | ||||||
|  |     } | ||||||
|  |     pub fn into_ptr(self) -> Type { | ||||||
|  |         Self::Pointer { | ||||||
|  |             constness: false, | ||||||
|  |             pointee: Box::new(self), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn can_logical_and_or(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Bool => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn can_negate(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Bool | Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn can_bitxor_and_or(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Bool | Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn can_add_sub(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Pointer { .. } | Type::Floating(_) | Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn can_shift(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn can_eq(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Pointer { .. } | Type::Bool | Type::Floating(_) | Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn can_cmp(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Pointer { .. } | Type::Floating(_) | Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn can_mul_div_rem(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Floating(_) | Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn is_integer(&self) -> bool { | ||||||
|  |         match self { | ||||||
|  |             Type::Integer(_) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn remove_ptr(self) -> crate::parser::Result<Self> { | ||||||
|  |         match self { | ||||||
|  |             Type::Pointer { pointee, .. } => Ok(Box::into_inner(pointee)), | ||||||
|  |             _ => Err(crate::parser::Error::TriedToDerefNonPointer), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn align_of(&self) -> u32 { | ||||||
|  |         self.size_of() | ||||||
|  |     } | ||||||
|  |     pub fn size_of(&self) -> u32 { | ||||||
|  |         match self { | ||||||
|  |             Type::Any => 0, | ||||||
|  |             Type::Void => 0, | ||||||
|  |             Type::Bool => 1, | ||||||
|  |             Type::Integer(t) => t.bits.div_ceil(8) as u32, | ||||||
|  |             Type::Floating(t) => match t { | ||||||
|  |                 FloatingType::Binary32 => 4, | ||||||
|  |                 FloatingType::Binary64 => 8, | ||||||
|  |             }, | ||||||
|  |             Type::Pointer { .. } => 8, | ||||||
|  |             Type::Fn { .. } => 8, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum PrimitiveType { | pub enum PrimitiveType { | ||||||
|     FloatingType(FloatingType), |     FloatingType(FloatingType), | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| #![feature(extract_if, iter_advance_by)] | #![feature(extract_if, iter_advance_by, box_into_inner)] | ||||||
| #![allow(dead_code, unused_macros)] | #![allow(dead_code, unused_macros)] | ||||||
| 
 | 
 | ||||||
| pub mod ast; | pub mod ast; | ||||||
|  | @ -6,6 +6,7 @@ pub mod common; | ||||||
| pub mod lexer; | pub mod lexer; | ||||||
| pub mod parser; | pub mod parser; | ||||||
| pub mod tokens; | pub mod tokens; | ||||||
|  | pub mod triples; | ||||||
| 
 | 
 | ||||||
| pub fn tokenize<'a>( | pub fn tokenize<'a>( | ||||||
|     bytes: &'a [u8], |     bytes: &'a [u8], | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ use std::collections::HashMap; | ||||||
| use itertools::Itertools; | use itertools::Itertools; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     ast::{FloatingType, IntegralType, LetOrVar, Node, PrimitiveType, Tag}, |     ast::{FloatingType, IntegralType, LetOrVar, Node, PrimitiveType, Tag, Type}, | ||||||
|     common::NextIf, |     common::NextIf, | ||||||
|     lexer::{Radix, TokenIterator}, |     lexer::{Radix, TokenIterator}, | ||||||
|     tokens::Token, |     tokens::Token, | ||||||
|  | @ -21,17 +21,22 @@ pub enum Error { | ||||||
|     ExpectedLetOrVar, |     ExpectedLetOrVar, | ||||||
|     #[error("Dummy message.")] |     #[error("Dummy message.")] | ||||||
|     IntegralTypeTooWide, |     IntegralTypeTooWide, | ||||||
|  |     #[error("Dummy message.")] | ||||||
|  |     TriedToDerefNonPointer, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub type Result<T> = core::result::Result<T, Error>; | pub type Result<T> = core::result::Result<T, Error>; | ||||||
| 
 | 
 | ||||||
|  | // TODO: add a string-table which stores strings and maybe other bytes and
 | ||||||
|  | // returns a range for identifiers, constants, etc. where bytes are stored
 | ||||||
|  | // flatly, and next to each other.
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Tree { | pub struct Tree { | ||||||
|     nodes: Vec<Tag>, |     nodes: Vec<Tag>, | ||||||
|     global_decls: Vec<Node>, |     pub global_decls: Vec<Node>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn write_indented_inner<W: core::fmt::Write>( | pub fn write_indented_inner<W: core::fmt::Write>( | ||||||
|     dst: &mut W, |     dst: &mut W, | ||||||
|     indent: u32, |     indent: u32, | ||||||
|     nl: bool, |     nl: bool, | ||||||
|  | @ -47,15 +52,17 @@ fn write_indented_inner<W: core::fmt::Write>( | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[macro_export] | ||||||
| macro_rules! write_indented { | macro_rules! write_indented { | ||||||
|     ($indent:expr, $w:expr, $($arg:tt)*) => { |     ($indent:expr, $w:expr, $($arg:tt)*) => { | ||||||
|         write_indented_inner($w, $indent, false, format_args!($($arg)*)) |         $crate::parser::write_indented_inner($w, $indent, false, format_args!($($arg)*)) | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[macro_export] | ||||||
| macro_rules! writeln_indented { | macro_rules! writeln_indented { | ||||||
|     ($indent:expr, $w:expr, $($arg:tt)*) => { |     ($indent:expr, $w:expr, $($arg:tt)*) => { | ||||||
|         write_indented_inner($w, $indent, true, format_args!($($arg)*)) |         $crate::parser::write_indented_inner($w, $indent, true, format_args!($($arg)*)) | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -73,18 +80,16 @@ impl Tree { | ||||||
|         node |         node | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn set_node(&mut self, node: Node, tag: Tag) -> Option<()> { |     fn set_node(&mut self, node: Node, tag: Tag) { | ||||||
|         *self.get_node_mut(node)? = tag; |         *self.get_node_mut(node) = tag; | ||||||
| 
 |  | ||||||
|         Some(()) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn get_node_mut(&mut self, node: Node) -> Option<&mut Tag> { |     fn get_node_mut(&mut self, node: Node) -> &mut Tag { | ||||||
|         self.nodes.get_mut(node.get() as usize) |         self.nodes.get_mut(node.get() as usize).unwrap() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn get_node(&self, node: Node) -> Option<&Tag> { |     pub fn get_node(&self, node: Node) -> &Tag { | ||||||
|         self.nodes.get(node.get() as usize) |         self.nodes.get(node.get() as usize).unwrap() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn push_tag(&mut self, tag: Tag) -> Node { |     fn push_tag(&mut self, tag: Tag) -> Node { | ||||||
|  | @ -301,10 +306,10 @@ impl Tree { | ||||||
|                 explicit_type, |                 explicit_type, | ||||||
|                 assignment, |                 assignment, | ||||||
|             }, |             }, | ||||||
|         ) |         ); | ||||||
|         .unwrap(); |  | ||||||
| 
 | 
 | ||||||
|         Ok(node) |         // return assignment if it exists, to make rendering and visiting easier
 | ||||||
|  |         Ok(assignment.unwrap_or(node)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn parse_global_decl(&mut self, tokens: &mut TokenIterator) -> Result<Node> { |     pub fn parse_global_decl(&mut self, tokens: &mut TokenIterator) -> Result<Node> { | ||||||
|  | @ -726,7 +731,7 @@ impl Tree { | ||||||
|         self.parse_program(&mut tokens) |         self.parse_program(&mut tokens) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn get_ident_str(&self, node: Node) -> Option<&str> { |     pub fn get_ident_str(&self, node: Node) -> Option<&str> { | ||||||
|         match &self.nodes[node.get() as usize] { |         match &self.nodes[node.get() as usize] { | ||||||
|             Tag::Ident { name } => Some(name.as_str()), |             Tag::Ident { name } => Some(name.as_str()), | ||||||
|             _ => None, |             _ => None, | ||||||
|  | @ -734,7 +739,7 @@ impl Tree { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn get_typename_str(&self, node: Node) -> Option<String> { |     fn get_typename_str(&self, node: Node) -> Option<String> { | ||||||
|         match self.get_node(node)? { |         match self.get_node(node) { | ||||||
|             Tag::IntegralType(i) => Some(i.to_string()), |             Tag::IntegralType(i) => Some(i.to_string()), | ||||||
|             Tag::Ident { name } => Some(name.clone()), |             Tag::Ident { name } => Some(name.clone()), | ||||||
|             Tag::Pointer { pointee } => self.get_typename_str(*pointee), |             Tag::Pointer { pointee } => self.get_typename_str(*pointee), | ||||||
|  | @ -769,7 +774,7 @@ impl Tree { | ||||||
|                 writeln!(writer, "}}") |                 writeln!(writer, "}}") | ||||||
|             } |             } | ||||||
|             Tag::ParameterList { parameters } => { |             Tag::ParameterList { parameters } => { | ||||||
|                 writeln_indented!(indent, writer, "%{} = ParameterList = [", node.get())?; |                 writeln_indented!(indent, writer, "%{} = ParameterList [", node.get())?; | ||||||
|                 for param in parameters { |                 for param in parameters { | ||||||
|                     self.render_node(writer, *param, indent + 1)?; |                     self.render_node(writer, *param, indent + 1)?; | ||||||
|                 } |                 } | ||||||
|  | @ -864,7 +869,7 @@ impl Tree { | ||||||
|                 let_or_var, |                 let_or_var, | ||||||
|                 name, |                 name, | ||||||
|                 explicit_type, |                 explicit_type, | ||||||
|                 assignment, |                 .. | ||||||
|             } => { |             } => { | ||||||
|                 self.render_node(writer, *name, indent)?; |                 self.render_node(writer, *name, indent)?; | ||||||
|                 explicit_type.map(|ty| self.render_node(writer, ty, indent)); |                 explicit_type.map(|ty| self.render_node(writer, ty, indent)); | ||||||
|  | @ -887,9 +892,6 @@ impl Tree { | ||||||
|                     write!(writer, ", ty: {}", self.get_typename_str(*ty).unwrap())?; |                     write!(writer, ", ty: {}", self.get_typename_str(*ty).unwrap())?; | ||||||
|                 } |                 } | ||||||
|                 writeln!(writer, ");")?; |                 writeln!(writer, ");")?; | ||||||
|                 if let Some(assignment) = assignment { |  | ||||||
|                     self.render_node(writer, *assignment, indent)?; |  | ||||||
|                 } |  | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|             } |             } | ||||||
|             Tag::CallExpr { lhs, rhs } => todo!(), |             Tag::CallExpr { lhs, rhs } => todo!(), | ||||||
|  | @ -1145,6 +1147,7 @@ impl Tree { | ||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|             Tag::Assign { lhs, rhs } => { |             Tag::Assign { lhs, rhs } => { | ||||||
|  |                 self.render_node(writer, *lhs, indent)?; | ||||||
|                 self.render_node(writer, *rhs, indent)?; |                 self.render_node(writer, *rhs, indent)?; | ||||||
|                 writeln_indented!( |                 writeln_indented!( | ||||||
|                     indent, |                     indent, | ||||||
|  |  | ||||||
							
								
								
									
										608
									
								
								src/triples.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										608
									
								
								src/triples.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,608 @@ | ||||||
|  | #![allow(dead_code)] | ||||||
|  | 
 | ||||||
|  | use std::{collections::HashMap, marker::PhantomData, num::NonZero}; | ||||||
|  | 
 | ||||||
|  | use crate::{ | ||||||
|  |     ast::{FloatingType, IntegralType, Node as AstNode, PrimitiveType, Tag, Type}, | ||||||
|  |     parser::Tree, | ||||||
|  |     writeln_indented, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SymbolRecord { | ||||||
|  |     name: String, | ||||||
|  |     decl: AstNode, | ||||||
|  |     ty: Type, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct SymbolTable<'a> { | ||||||
|  |     tree: &'a Tree, | ||||||
|  |     identifiers: Vec<SymbolRecord>, | ||||||
|  |     parent: Option<Box<SymbolTable<'a>>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> SymbolTable<'a> { | ||||||
|  |     pub fn root(tree: &'a Tree) -> Self { | ||||||
|  |         Self { | ||||||
|  |             tree, | ||||||
|  |             identifiers: Vec::new(), | ||||||
|  |             parent: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn insert_symbol_with_name(&mut self, ast_node: AstNode, name: String) { | ||||||
|  |         let ty = self.type_of_node(ast_node); | ||||||
|  |         self.identifiers.push(SymbolRecord { | ||||||
|  |             name, | ||||||
|  |             decl: ast_node, | ||||||
|  |             ty, | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn insert_return_symbol(&mut self, ast_node: AstNode) { | ||||||
|  |         self.insert_symbol_with_name(ast_node, "return".to_string()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn insert_symbol(&mut self, ast_node: AstNode) { | ||||||
|  |         let name = match self.tree.get_node(ast_node) { | ||||||
|  |             Tag::VarDecl { name, .. } => self.tree.get_ident_str(*name).unwrap().to_string(), | ||||||
|  |             Tag::Parameter { name, .. } => self.tree.get_ident_str(*name).unwrap().to_string(), | ||||||
|  |             Tag::FunctionProto { name, .. } => self.tree.get_ident_str(*name).unwrap().to_string(), | ||||||
|  |             _ => { | ||||||
|  |                 panic!("ast_node wasn't any kind of decl!"); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.insert_symbol_with_name(ast_node, name) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn find_symbol_name(&self, name: &str) -> Option<&SymbolRecord> { | ||||||
|  |         self.identifiers | ||||||
|  |             .iter() | ||||||
|  |             .find(|r| r.name.as_str() == name) | ||||||
|  |             .or_else(|| { | ||||||
|  |                 self.parent | ||||||
|  |                     .as_ref() | ||||||
|  |                     .and_then(|parent| parent.find_symbol_name(name)) | ||||||
|  |             }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn find_symbol(&self, ident_node: AstNode) -> Option<&SymbolRecord> { | ||||||
|  |         self.identifiers | ||||||
|  |             .iter() | ||||||
|  |             .find(|r| Some(r.name.as_str()) == self.tree.get_ident_str(ident_node)) | ||||||
|  |             .or_else(|| { | ||||||
|  |                 self.parent | ||||||
|  |                     .as_ref() | ||||||
|  |                     .and_then(|parent| parent.find_symbol(ident_node)) | ||||||
|  |             }) | ||||||
|  |     } | ||||||
|  |     pub fn into_child_in_place(&mut self) { | ||||||
|  |         let mut parent = Self { | ||||||
|  |             parent: None, | ||||||
|  |             tree: self.tree, | ||||||
|  |             identifiers: Vec::new(), | ||||||
|  |         }; | ||||||
|  |         core::mem::swap(self, &mut parent); | ||||||
|  |         self.parent = Some(Box::new(parent)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn into_child(self) -> SymbolTable<'a> { | ||||||
|  |         Self { | ||||||
|  |             identifiers: Vec::new(), | ||||||
|  |             tree: self.tree, | ||||||
|  |             parent: Some(Box::new(self)), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn parent_mut(&mut self) -> Option<&mut SymbolTable<'a>> { | ||||||
|  |         self.parent.as_mut().map(|parent| parent.as_mut()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn into_parent_in_place(&mut self) -> Option<SymbolTable<'a>> { | ||||||
|  |         if let Some(child) = self.parent.take() { | ||||||
|  |             let mut child = Box::into_inner(child); | ||||||
|  |             core::mem::swap(self, &mut child); | ||||||
|  |             Some(child) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn into_parent(self) -> Option<SymbolTable<'a>> { | ||||||
|  |         self.parent.map(|parent| Box::into_inner(parent)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn type_of_node(&self, node: AstNode) -> crate::ast::Type { | ||||||
|  |         match self.tree.get_node(node) { | ||||||
|  |             Tag::Ident { name } => self | ||||||
|  |                 .find_symbol(node) | ||||||
|  |                 .map(|r| r.ty.clone()) | ||||||
|  |                 .expect(&format!("identifier '{name}' not found in SymbolTable!")), | ||||||
|  |             Tag::FunctionDecl { proto, .. } => self.type_of_node(*proto), | ||||||
|  |             Tag::FunctionProto { | ||||||
|  |                 parameters, | ||||||
|  |                 return_type, | ||||||
|  |                 .. | ||||||
|  |             } => { | ||||||
|  |                 let return_type = self.type_of_node(*return_type); | ||||||
|  |                 let parameter_types = parameters | ||||||
|  |                     .map(|p| match self.tree.get_node(p) { | ||||||
|  |                         Tag::ParameterList { parameters } => parameters | ||||||
|  |                             .iter() | ||||||
|  |                             .map(|p| self.type_of_node(*p)) | ||||||
|  |                             .collect::<Vec<_>>(), | ||||||
|  |                         _ => panic!("parameters is not a parameterlist!"), | ||||||
|  |                     }) | ||||||
|  |                     .unwrap_or(Vec::new()); | ||||||
|  | 
 | ||||||
|  |                 crate::ast::Type::Fn { | ||||||
|  |                     parameter_types, | ||||||
|  |                     return_type: Box::new(return_type), | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Tag::Parameter { ty, .. } => self.type_of_node(*ty), | ||||||
|  |             Tag::Pointer { pointee } => Type::Pointer { | ||||||
|  |                 constness: false, | ||||||
|  |                 pointee: Box::new(self.type_of_node(*pointee)), | ||||||
|  |             }, | ||||||
|  |             Tag::IntegralType(t) => Type::Integer(*t), | ||||||
|  |             Tag::PrimitiveType(t) => match t { | ||||||
|  |                 PrimitiveType::FloatingType(t) => Type::Floating(*t), | ||||||
|  |                 PrimitiveType::IntegralType(t) => self.type_of_node(*t), | ||||||
|  |                 PrimitiveType::Bool => Type::bool(), | ||||||
|  |                 PrimitiveType::Void => Type::void(), | ||||||
|  |             }, | ||||||
|  |             Tag::IntegralConstant { ty, .. } => Type::Integer(*ty), | ||||||
|  |             Tag::FloatingConstant { ty, .. } => Type::Floating(*ty), | ||||||
|  |             Tag::Block { trailing_expr, .. } => trailing_expr | ||||||
|  |                 .map(|n| self.type_of_node(n)) | ||||||
|  |                 .unwrap_or(Type::void()), | ||||||
|  |             Tag::VarDecl { | ||||||
|  |                 explicit_type, | ||||||
|  |                 assignment, // this is a Tag::Assign
 | ||||||
|  |                 .. | ||||||
|  |             } => { | ||||||
|  |                 let lhs = explicit_type.map(|n| self.type_of_node(n)); | ||||||
|  |                 let rhs = assignment.map(|n| match self.tree.get_node(n) { | ||||||
|  |                     Tag::Assign { rhs, .. } => self.type_of_node(*rhs), | ||||||
|  |                     _ => unreachable!(), | ||||||
|  |                 }); | ||||||
|  |                 if lhs.as_ref().zip(rhs.as_ref()).map(|(l, r)| l != r) == Some(true) { | ||||||
|  |                     eprintln!("vardecl: incompatible types {lhs:?} and {rhs:?}."); | ||||||
|  |                 } | ||||||
|  |                 lhs.or(rhs) | ||||||
|  |                     .expect("Type could not be automatically deduced.") | ||||||
|  |             } | ||||||
|  |             Tag::CallExpr { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::ExplicitCast { typename, .. } => self.type_of_node(*typename), | ||||||
|  |             Tag::Deref { lhs } => self.type_of_node(*lhs).remove_ptr().unwrap(), | ||||||
|  |             Tag::Ref { lhs } => self.type_of_node(*lhs).into_ptr(), | ||||||
|  |             Tag::Not { lhs } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Negate { lhs } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Or { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::And { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::BitOr { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::BitAnd { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::BitXOr { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Shl { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Shr { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Add { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Sub { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Mul { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Rem { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Div { lhs, .. } => self.type_of_node(*lhs), | ||||||
|  |             Tag::Eq { .. } => Type::bool(), | ||||||
|  |             Tag::NEq { .. } => Type::bool(), | ||||||
|  |             Tag::Lt { .. } => Type::bool(), | ||||||
|  |             Tag::Gt { .. } => Type::bool(), | ||||||
|  |             Tag::Le { .. } => Type::bool(), | ||||||
|  |             Tag::Ge { .. } => Type::bool(), | ||||||
|  |             _ => Type::void(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Node = u32; | ||||||
|  | 
 | ||||||
|  | enum Inst { | ||||||
|  |     Label(String), | ||||||
|  |     Constant(Value), | ||||||
|  |     Parameter, | ||||||
|  |     Add { lhs: Node, rhs: Node }, | ||||||
|  |     Sub { lhs: Node, rhs: Node }, | ||||||
|  |     Div { lhs: Node, rhs: Node }, | ||||||
|  |     Mul { lhs: Node, rhs: Node }, | ||||||
|  |     Rem { lhs: Node, rhs: Node }, | ||||||
|  |     BitAnd { lhs: Node, rhs: Node }, | ||||||
|  |     BitOr { lhs: Node, rhs: Node }, | ||||||
|  |     BitXOr { lhs: Node, rhs: Node }, | ||||||
|  |     Negate { lhs: Node }, | ||||||
|  |     ReturnValue { lhs: Node }, | ||||||
|  |     Return, | ||||||
|  |     Alloc { size: u32, align: u32 }, | ||||||
|  |     AddressOf(Node), | ||||||
|  |     Load { source: Node }, | ||||||
|  |     Store { dest: Node, source: Node }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | enum Value { | ||||||
|  |     Int { kind: IntegralType, bits: u64 }, | ||||||
|  |     Float { kind: FloatingType, bits: u64 }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl core::fmt::Display for Value { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |         match self { | ||||||
|  |             Value::Int { kind, bits } => { | ||||||
|  |                 write!(f, "{kind} {}", bits) | ||||||
|  |             } | ||||||
|  |             Value::Float { kind, bits } => { | ||||||
|  |                 write!(f, "{kind} {{{}}}", bits) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct IRBuilder<'tree, 'ir> { | ||||||
|  |     ir: &'ir mut IR, | ||||||
|  |     st: SymbolTable<'tree>, | ||||||
|  |     lookup: HashMap<AstNode, Node>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'tree, 'ir> IRBuilder<'tree, 'ir> { | ||||||
|  |     fn new(ir: &'ir mut IR, st: SymbolTable<'tree>) -> Self { | ||||||
|  |         Self { | ||||||
|  |             ir, | ||||||
|  |             st, | ||||||
|  |             lookup: HashMap::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn visit(&mut self, node: AstNode) -> Node { | ||||||
|  |         println!("visiting %{}", node.get()); | ||||||
|  |         match self.st.tree.get_node(node) { | ||||||
|  |             Tag::FunctionDecl { proto, body } => { | ||||||
|  |                 self.visit(*proto); | ||||||
|  |                 self.st.into_child_in_place(); | ||||||
|  |                 let value = self.visit(*body); | ||||||
|  |                 // TODO: return value of body expression
 | ||||||
|  |                 let node = if value != !0 { | ||||||
|  |                     self.type_check(self.st.find_symbol_name("return").unwrap().decl, *body); | ||||||
|  |                     self.ir.push(Inst::ReturnValue { lhs: value }) | ||||||
|  |                 } else { | ||||||
|  |                     !0 | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 self.st.into_parent_in_place(); | ||||||
|  |                 node | ||||||
|  |             } | ||||||
|  |             Tag::FunctionProto { | ||||||
|  |                 parameters, | ||||||
|  |                 return_type, | ||||||
|  |                 name, | ||||||
|  |             } => { | ||||||
|  |                 self.st.insert_symbol(node); | ||||||
|  |                 self.st.insert_return_symbol(*return_type); | ||||||
|  |                 parameters.map(|p| self.visit(p)); | ||||||
|  | 
 | ||||||
|  |                 let label = self.ir.push(Inst::Label( | ||||||
|  |                     self.st.tree.get_ident_str(*name).unwrap().to_string(), | ||||||
|  |                 )); | ||||||
|  | 
 | ||||||
|  |                 self.lookup.insert(node, label); | ||||||
|  | 
 | ||||||
|  |                 label | ||||||
|  |             } | ||||||
|  |             Tag::ParameterList { parameters } => { | ||||||
|  |                 for param in parameters { | ||||||
|  |                     self.visit(*param); | ||||||
|  |                 } | ||||||
|  |                 !0 | ||||||
|  |             } | ||||||
|  |             Tag::Parameter { .. } => { | ||||||
|  |                 self.st.insert_symbol(node); | ||||||
|  |                 let param = self.ir.push(Inst::Parameter); | ||||||
|  | 
 | ||||||
|  |                 self.lookup.insert(node, param); | ||||||
|  |                 param | ||||||
|  |             } | ||||||
|  |             Tag::Block { | ||||||
|  |                 statements, | ||||||
|  |                 trailing_expr, | ||||||
|  |             } => { | ||||||
|  |                 for stmt in statements { | ||||||
|  |                     self.visit(*stmt); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if let Some(expr) = trailing_expr { | ||||||
|  |                     self.visit(*expr) | ||||||
|  |                 } else { | ||||||
|  |                     !0 | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Tag::VarDecl { .. } => { | ||||||
|  |                 let ty = self.st.type_of_node(node); | ||||||
|  |                 let alloca = self.ir.push(Inst::Alloc { | ||||||
|  |                     size: ty.size_of(), | ||||||
|  |                     align: ty.align_of(), | ||||||
|  |                 }); | ||||||
|  |                 self.st.insert_symbol(node); | ||||||
|  |                 self.lookup.insert(node, alloca); | ||||||
|  |                 alloca | ||||||
|  |             } | ||||||
|  |             Tag::ReturnStmt { expr } => { | ||||||
|  |                 if let Some(expr) = expr { | ||||||
|  |                     let expr = self.visit(*expr); | ||||||
|  |                     self.ir.push(Inst::ReturnValue { lhs: expr }) | ||||||
|  |                 } else { | ||||||
|  |                     self.ir.push(Inst::Return) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Tag::ExprStmt { expr } => self.visit(*expr), | ||||||
|  |             Tag::Deref { lhs } => { | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 self.ir.push(Inst::Load { source: lhs }) | ||||||
|  |             } | ||||||
|  |             Tag::IntegralConstant { bits, ty } => self.ir.push(Inst::Constant(Value::Int { | ||||||
|  |                 kind: *ty, | ||||||
|  |                 bits: *bits, | ||||||
|  |             })), | ||||||
|  |             Tag::FloatingConstant { bits, ty } => self.ir.push(Inst::Constant(Value::Float { | ||||||
|  |                 kind: *ty, | ||||||
|  |                 bits: *bits, | ||||||
|  |             })), | ||||||
|  |             Tag::Assign { lhs, rhs } => { | ||||||
|  |                 self.type_check(*lhs, *rhs); | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::Store { | ||||||
|  |                     dest: lhs, | ||||||
|  |                     source: rhs, | ||||||
|  |                 }) | ||||||
|  |             } | ||||||
|  |             Tag::Add { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_add_sub() { | ||||||
|  |                     eprintln!("add is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::Add { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::Sub { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_add_sub() { | ||||||
|  |                     eprintln!("sub is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::Sub { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::Mul { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_mul_div_rem() { | ||||||
|  |                     eprintln!("mul is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::Mul { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::Div { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_mul_div_rem() { | ||||||
|  |                     eprintln!("div is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::Div { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::Rem { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_mul_div_rem() { | ||||||
|  |                     eprintln!("rem is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::Rem { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::BitAnd { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_bitxor_and_or() { | ||||||
|  |                     eprintln!("bitand is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::BitAnd { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::BitOr { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_bitxor_and_or() { | ||||||
|  |                     eprintln!("bitor is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::BitOr { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::BitXOr { lhs, rhs } => { | ||||||
|  |                 let ty = self.type_check(*lhs, *rhs); | ||||||
|  |                 if !ty.can_bitxor_and_or() { | ||||||
|  |                     eprintln!("bitxor is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 let rhs = self.visit(*rhs); | ||||||
|  |                 self.ir.push(Inst::BitXOr { lhs, rhs }) | ||||||
|  |             } | ||||||
|  |             Tag::Negate { lhs } => { | ||||||
|  |                 let ty = self.st.type_of_node(*lhs); | ||||||
|  |                 if !ty.can_negate() { | ||||||
|  |                     eprintln!("negation is not available for type {ty:?}"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 self.ir.push(Inst::Negate { lhs }) | ||||||
|  |             } | ||||||
|  |             Tag::Ident { name } => { | ||||||
|  |                 let decl = self | ||||||
|  |                     .st | ||||||
|  |                     .find_symbol(node) | ||||||
|  |                     .expect(&format!("symbol '{name}' not found in SymbolMap!")) | ||||||
|  |                     .decl; | ||||||
|  | 
 | ||||||
|  |                 *self.lookup.get(&decl).unwrap() | ||||||
|  |             } | ||||||
|  |             Tag::Ref { lhs } => { | ||||||
|  |                 let lhs = self.visit(*lhs); | ||||||
|  |                 self.ir.push(Inst::AddressOf(lhs)) | ||||||
|  |             } | ||||||
|  |             _ => { | ||||||
|  |                 dbg!(self.st.tree.get_node(node)); | ||||||
|  |                 todo!() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn type_check(&self, lhs: AstNode, rhs: AstNode) -> Type { | ||||||
|  |         let t_lhs = self.st.type_of_node(lhs); | ||||||
|  |         let t_rhs = self.st.type_of_node(rhs); | ||||||
|  |         if t_lhs != t_rhs { | ||||||
|  |             eprintln!("incompatible types {t_lhs:?} and {t_rhs:?}!"); | ||||||
|  |         } | ||||||
|  |         t_lhs | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct IR { | ||||||
|  |     nodes: Vec<Inst>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl IR { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self { nodes: Vec::new() } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn push(&mut self, inst: Inst) -> u32 { | ||||||
|  |         let node = self.nodes.len() as u32; | ||||||
|  |         self.nodes.push(inst); | ||||||
|  |         node | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn build(&mut self, tree: &Tree, ast_node: crate::ast::Node) { | ||||||
|  |         let st = SymbolTable::root(tree); | ||||||
|  |         let mut builder = IRBuilder::new(self, st); | ||||||
|  | 
 | ||||||
|  |         builder.visit(ast_node); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn render_node<W: core::fmt::Write>( | ||||||
|  |         &self, | ||||||
|  |         w: &mut W, | ||||||
|  |         node: Node, | ||||||
|  |         indent: u32, | ||||||
|  |     ) -> core::fmt::Result { | ||||||
|  |         match &self.nodes[node as usize] { | ||||||
|  |             Inst::Label(label) => { | ||||||
|  |                 writeln_indented!(indent - 1, w, "%{} = {label}:", node)?; | ||||||
|  |             } | ||||||
|  |             Inst::Parameter => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = Param", node)?; | ||||||
|  |             } | ||||||
|  |             Inst::Constant(value) => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = {}", node, value)?; | ||||||
|  |             } | ||||||
|  |             Inst::Add { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} + %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::Sub { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} - %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::Mul { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} * %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::Div { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} / %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::Rem { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} % %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::BitAnd { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} & %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::BitOr { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} | %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::BitXOr { lhs, rhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = %{} ^ %{}", node, lhs, rhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::Negate { lhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = !%{}", node, lhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::ReturnValue { lhs } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = return %{}", node, lhs)?; | ||||||
|  |             } | ||||||
|  |             Inst::Return => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = return", node)?; | ||||||
|  |             } | ||||||
|  |             Inst::Alloc { size, align } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = alloca {size} (algin: {align})", node)?; | ||||||
|  |             } | ||||||
|  |             Inst::AddressOf(val) => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = addr %{val}", node)?; | ||||||
|  |             } | ||||||
|  |             Inst::Load { source } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = load ptr %{source}", node)?; | ||||||
|  |             } | ||||||
|  |             Inst::Store { dest, source } => { | ||||||
|  |                 writeln_indented!(indent, w, "%{} = store ptr %{dest} from %{source}", node)?; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn render<W: core::fmt::Write>(&self, w: &mut W) -> core::fmt::Result { | ||||||
|  |         for node in 0..self.nodes.len() { | ||||||
|  |             self.render_node(w, node as u32, 1)?; | ||||||
|  |         } | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use crate::lexer::Tokenizer; | ||||||
|  | 
 | ||||||
|  |     use super::*; | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn ir() { | ||||||
|  |         let src = " | ||||||
|  | fn main() -> u32 { | ||||||
|  | let a: u32 = 0 + 3; | ||||||
|  | let ptr_a = &a; | ||||||
|  | return *ptr_a * 2; | ||||||
|  | } | ||||||
|  | ";
 | ||||||
|  |         let tokens = Tokenizer::new(src.as_bytes()).unwrap(); | ||||||
|  | 
 | ||||||
|  |         let mut tree = Tree::new(); | ||||||
|  |         tree.parse(tokens.iter()).unwrap(); | ||||||
|  | 
 | ||||||
|  |         let mut buf = String::new(); | ||||||
|  |         tree.render(&mut buf).unwrap(); | ||||||
|  |         println!("{buf}"); | ||||||
|  | 
 | ||||||
|  |         let mut ir = IR::new(); | ||||||
|  |         ir.build(&tree, *tree.global_decls.first().unwrap()); | ||||||
|  |         let mut buf = String::new(); | ||||||
|  |         ir.render(&mut buf).unwrap(); | ||||||
|  |         println!("{buf}"); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in a new issue