Compare commits
	
		
			9 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 384703fbd2 | |||
| 107303aa98 | |||
| 08626c8559 | |||
| ffb3515aaa | |||
| 1e4667449a | |||
| 6fbb26ba88 | |||
| 91fd0d4d5a | |||
| 13e462def7 | |||
| ff83d7b4f0 | 
							
								
								
									
										10
									
								
								examples/generics.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								examples/generics.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| // Arithmetic, function calls and imports! | ||||
| 
 | ||||
| fn test<T>(value: T) -> T { | ||||
|   let b: T = value; | ||||
|   return b; | ||||
| } | ||||
| 
 | ||||
| fn main() -> u32 { | ||||
|   return test<u64>(15) as u32 + test<u32>(5); | ||||
| } | ||||
| @ -16,7 +16,7 @@ BINARY="$(echo $1 | cut -d'.' -f1)"".out" | ||||
| 
 | ||||
| echo $1 | ||||
| 
 | ||||
| cargo run -p reid -- $@ && \ | ||||
| cargo run -p reid -- run $@ && \ | ||||
| ./$BINARY ; echo "Return value: ""$?" | ||||
| 
 | ||||
| ## Command from: clang -v hello.o -o test | ||||
|  | ||||
| @ -162,6 +162,7 @@ impl BinaryOperator { | ||||
| pub struct FunctionCallExpression { | ||||
|     pub name: String, | ||||
|     pub params: Vec<Expression>, | ||||
|     pub generics: Vec<Type>, | ||||
|     pub range: TokenRange, | ||||
|     pub is_macro: bool, | ||||
| } | ||||
| @ -192,6 +193,7 @@ pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub To | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct FunctionSignature { | ||||
|     pub name: String, | ||||
|     pub generics: Vec<String>, | ||||
|     pub documentation: Option<String>, | ||||
|     pub self_kind: SelfKind, | ||||
|     pub params: Vec<(String, Type, TokenRange)>, | ||||
|  | ||||
| @ -182,6 +182,7 @@ impl Parse for AssociatedFunctionCall { | ||||
|                 ty, | ||||
|                 FunctionCallExpression { | ||||
|                     name: String::new(), | ||||
|                     generics: Vec::new(), | ||||
|                     params: Vec::new(), | ||||
|                     range: stream.get_range_prev_curr().unwrap(), | ||||
|                     is_macro: false, | ||||
| @ -200,6 +201,7 @@ impl Parse for AssociatedFunctionCall { | ||||
|                         ty, | ||||
|                         FunctionCallExpression { | ||||
|                             name: fn_name, | ||||
|                             generics: Vec::new(), | ||||
|                             params: Vec::new(), | ||||
|                             range: stream.get_range_prev_curr().unwrap(), | ||||
|                             is_macro: false, | ||||
| @ -211,6 +213,7 @@ impl Parse for AssociatedFunctionCall { | ||||
|                         ty, | ||||
|                         FunctionCallExpression { | ||||
|                             name: String::new(), | ||||
|                             generics: Vec::new(), | ||||
|                             params: Vec::new(), | ||||
|                             range: stream.get_range_prev_curr().unwrap(), | ||||
|                             is_macro: false, | ||||
| @ -591,7 +594,8 @@ impl Parse for FunctionCallExpression { | ||||
|             let args = stream.parse::<FunctionArgs>()?; | ||||
|             Ok(FunctionCallExpression { | ||||
|                 name, | ||||
|                 params: args.0, | ||||
|                 generics: args.0, | ||||
|                 params: args.1, | ||||
|                 range: stream.get_range().unwrap(), | ||||
|                 is_macro, | ||||
|             }) | ||||
| @ -602,10 +606,23 @@ impl Parse for FunctionCallExpression { | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct FunctionArgs(Vec<Expression>); | ||||
| pub struct FunctionArgs(Vec<Type>, Vec<Expression>); | ||||
| 
 | ||||
| impl Parse for FunctionArgs { | ||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||
|         let mut generics: Vec<Type> = Vec::new(); | ||||
|         if let Some(Token::LessThan) = stream.peek() { | ||||
|             stream.next(); | ||||
|             if let Ok(ty) = stream.parse() { | ||||
|                 generics.push(ty); | ||||
|                 while let Some(Token::Comma) = stream.peek() { | ||||
|                     stream.next(); | ||||
|                     generics.push(stream.parse()?); | ||||
|                 } | ||||
|             } | ||||
|             stream.expect(Token::GreaterThan)?; | ||||
|         } | ||||
| 
 | ||||
|         stream.expect(Token::ParenOpen)?; | ||||
| 
 | ||||
|         let mut params = Vec::new(); | ||||
| @ -618,7 +635,7 @@ impl Parse for FunctionArgs { | ||||
|         } | ||||
|         stream.expect(Token::ParenClose)?; | ||||
| 
 | ||||
|         Ok(FunctionArgs(params)) | ||||
|         Ok(FunctionArgs(generics, params)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -780,6 +797,18 @@ impl Parse for SelfParam { | ||||
| impl Parse for FunctionSignature { | ||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||
|         if let Some(Token::Identifier(name)) = stream.next() { | ||||
|             let mut generics = Vec::new(); | ||||
| 
 | ||||
|             if let Some(Token::LessThan) = stream.peek() { | ||||
|                 stream.next(); | ||||
|                 while let Some(Token::Identifier(ident)) = stream.peek() { | ||||
|                     stream.next(); | ||||
|                     generics.push(ident); | ||||
|                 } | ||||
| 
 | ||||
|                 stream.expect(Token::GreaterThan)?; | ||||
|             } | ||||
| 
 | ||||
|             stream.expect(Token::ParenOpen)?; | ||||
|             let mut params = Vec::new(); | ||||
| 
 | ||||
| @ -814,6 +843,7 @@ impl Parse for FunctionSignature { | ||||
| 
 | ||||
|             Ok(FunctionSignature { | ||||
|                 name, | ||||
|                 generics, | ||||
|                 documentation: None, | ||||
|                 params, | ||||
|                 self_kind, | ||||
| @ -961,7 +991,8 @@ impl Parse for DotIndexKind { | ||||
|             if let Ok(args) = stream.parse::<FunctionArgs>() { | ||||
|                 Ok(Self::FunctionCall(FunctionCallExpression { | ||||
|                     name, | ||||
|                     params: args.0, | ||||
|                     generics: args.0, | ||||
|                     params: args.1, | ||||
|                     range: stream.get_range_prev().unwrap(), | ||||
|                     is_macro: false, | ||||
|                 })) | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use std::path::PathBuf; | ||||
| use std::{collections::HashMap, path::PathBuf}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     ast::{self, ReturnType}, | ||||
|     ast::{self, ReturnType, TypeKind}, | ||||
|     mir::{ | ||||
|         self, CustomTypeKey, FunctionParam, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind, | ||||
|         StructField, StructType, WhileStatement, | ||||
| @ -44,6 +44,11 @@ impl ast::Module { | ||||
|                     let def = mir::FunctionDefinition { | ||||
|                         name: signature.name.clone(), | ||||
|                         documentation: signature.documentation.clone(), | ||||
|                         generics: signature | ||||
|                             .generics | ||||
|                             .iter() | ||||
|                             .map(|g| (g.clone(), mir::TypeKind::Vague(mir::VagueType::Unknown))) | ||||
|                             .collect(), | ||||
|                         linkage_name: None, | ||||
|                         is_pub: false, | ||||
|                         is_imported: false, | ||||
| @ -175,9 +180,15 @@ impl ast::FunctionDefinition { | ||||
|             ty: p.1 .0.into_mir(module_id), | ||||
|             meta: p.2.as_meta(module_id), | ||||
|         })); | ||||
| 
 | ||||
|         mir::FunctionDefinition { | ||||
|             name: signature.name.clone(), | ||||
|             documentation: signature.documentation.clone(), | ||||
|             generics: signature | ||||
|                 .generics | ||||
|                 .iter() | ||||
|                 .map(|g| (g.clone(), mir::TypeKind::Vague(mir::VagueType::Unknown))) | ||||
|                 .collect(), | ||||
|             linkage_name: None, | ||||
|             is_pub: *is_pub, | ||||
|             is_imported: false, | ||||
| @ -379,6 +390,7 @@ impl ast::Expression { | ||||
|             ), | ||||
|             ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall { | ||||
|                 name: fn_call_expr.name.clone(), | ||||
|                 generics: fn_call_expr.generics.iter().map(|g| g.0.into_mir(module_id)).collect(), | ||||
|                 return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), | ||||
|                 parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(), | ||||
|                 meta: fn_call_expr.range.as_meta(module_id), | ||||
| @ -468,6 +480,7 @@ impl ast::Expression { | ||||
|                 ty.0.into_mir(module_id), | ||||
|                 mir::FunctionCall { | ||||
|                     name: fn_call_expr.name.clone(), | ||||
|                     generics: fn_call_expr.generics.iter().map(|g| g.0.into_mir(module_id)).collect(), | ||||
|                     return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), | ||||
|                     parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(), | ||||
|                     meta: fn_call_expr.range.as_meta(module_id), | ||||
| @ -491,6 +504,7 @@ impl ast::Expression { | ||||
|                     mir::TypeKind::Vague(mir::VagueType::Unknown), | ||||
|                     mir::FunctionCall { | ||||
|                         name: fn_call_expr.name.clone(), | ||||
|                         generics: fn_call_expr.generics.iter().map(|g| g.0.into_mir(module_id)).collect(), | ||||
|                         return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), | ||||
|                         parameters: params, | ||||
|                         meta: fn_call_expr.range.as_meta(module_id), | ||||
|  | ||||
| @ -77,6 +77,7 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> { | ||||
| 
 | ||||
|     intrinsics.push(FunctionDefinition { | ||||
|         name: MALLOC_IDENT.to_owned(), | ||||
|         generics: Vec::new(), | ||||
|         documentation: doc!("Allocates `size` bytes and returns a `u8`-pointer."), | ||||
|         linkage_name: Some("malloc".to_owned()), | ||||
|         is_pub: false, | ||||
| @ -104,6 +105,7 @@ pub fn simple_intrinsic<T: Into<String> + Clone>( | ||||
| ) -> FunctionDefinition { | ||||
|     FunctionDefinition { | ||||
|         name: name.into(), | ||||
|         generics: Vec::new(), | ||||
|         documentation: Some(doc.into()), | ||||
|         linkage_name: None, | ||||
|         is_pub: true, | ||||
| @ -124,6 +126,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
|     if let TypeKind::Array(_, len) = ty { | ||||
|         intrinsics.push(FunctionDefinition { | ||||
|             name: "length".to_owned(), | ||||
|             generics: Vec::new(), | ||||
|             documentation: doc!("Returns the length of this given array"), | ||||
|             linkage_name: None, | ||||
|             is_pub: true, | ||||
| @ -282,6 +285,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
|         )); | ||||
|         intrinsics.push(FunctionDefinition { | ||||
|             name: "powi".to_owned(), | ||||
|             generics: Vec::new(), | ||||
|             documentation: doc!("Returns `value` raised to the exponent of `exponent`."), | ||||
|             linkage_name: None, | ||||
|             is_pub: true, | ||||
| @ -326,6 +330,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
|             if ty.signed() { | ||||
|                 intrinsics.push(FunctionDefinition { | ||||
|                     name: "abs".to_owned(), | ||||
|                     generics: Vec::new(), | ||||
|                     documentation: doc!("Returns the absolute value of `value`."), | ||||
|                     linkage_name: None, | ||||
|                     is_pub: true, | ||||
| @ -357,6 +362,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
|     } | ||||
|     intrinsics.push(FunctionDefinition { | ||||
|         name: "sizeof".to_owned(), | ||||
|         generics: Vec::new(), | ||||
|         documentation: doc!("Simply returns the size of type `T` in bytes."), | ||||
|         linkage_name: None, | ||||
|         is_pub: true, | ||||
| @ -369,6 +375,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
|     }); | ||||
|     intrinsics.push(FunctionDefinition { | ||||
|         name: "malloc".to_owned(), | ||||
|         generics: Vec::new(), | ||||
|         documentation: doc!("Allocates `T::sizeof() * size` bytes and returns a pointer to `T`."), | ||||
|         linkage_name: None, | ||||
|         is_pub: true, | ||||
| @ -386,6 +393,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
| 
 | ||||
|     intrinsics.push(FunctionDefinition { | ||||
|         name: "memcpy".to_owned(), | ||||
|         generics: Vec::new(), | ||||
|         documentation: doc!( | ||||
|             "Copies `T::sizeof() * size` bytes from pointer `source` to pointer
 | ||||
| `destination`." | ||||
| @ -418,6 +426,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
| 
 | ||||
|     intrinsics.push(FunctionDefinition { | ||||
|         name: "null".to_owned(), | ||||
|         generics: Vec::new(), | ||||
|         documentation: doc!("Returns a null-pointer of type `T`."), | ||||
|         linkage_name: None, | ||||
|         is_pub: true, | ||||
| @ -431,6 +440,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
| 
 | ||||
|     intrinsics.push(FunctionDefinition { | ||||
|         name: "is_null".to_owned(), | ||||
|         generics: Vec::new(), | ||||
|         documentation: doc!("Returns a boolean representing if `val` is a nullptr or not."), | ||||
|         linkage_name: None, | ||||
|         is_pub: true, | ||||
|  | ||||
| @ -1218,7 +1218,9 @@ impl mir::Expression { | ||||
|                 let TypeKind::CustomType(key) = *inner.clone() else { | ||||
|                     panic!("tried accessing non-custom-type"); | ||||
|                 }; | ||||
|                 let TypeDefinitionKind::Struct(struct_ty) = scope.get_typedef(&key).unwrap().kind.clone(); | ||||
|                 let TypeDefinitionKind::Struct(struct_ty) = scope.get_typedef(&key).unwrap().kind.clone() else { | ||||
|                     panic!(); | ||||
|                 }; | ||||
|                 let idx = struct_ty.find_index(field).unwrap(); | ||||
| 
 | ||||
|                 let gep_n = format!("{}.{}.gep", key.0, field); | ||||
| @ -1259,7 +1261,10 @@ impl mir::Expression { | ||||
|                 let TypeDefinition { | ||||
|                     kind: TypeDefinitionKind::Struct(struct_ty), | ||||
|                     .. | ||||
|                 } = scope.types.get(scope.type_values.get(&key).unwrap()).unwrap(); | ||||
|                 } = scope.types.get(scope.type_values.get(&key).unwrap()).unwrap() | ||||
|                 else { | ||||
|                     panic!() | ||||
|                 }; | ||||
| 
 | ||||
|                 let indices = struct_ty.0.iter().enumerate(); | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ use crate::{ | ||||
|     ast::token_stream::{self, TokenRange}, | ||||
|     codegen, | ||||
|     lexer::{self, Cursor, FullToken, Position}, | ||||
|     mir::{self, macros, pass, typecheck, Metadata, SourceModuleId}, | ||||
|     mir::{self, generics, macros, pass, typecheck, Metadata, SourceModuleId}, | ||||
| }; | ||||
| 
 | ||||
| use crate::mir::typecheck::ErrorKind as TypecheckError; | ||||
| @ -36,6 +36,8 @@ pub enum ErrorKind { | ||||
|     LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), | ||||
|     #[error("{}{}", label("(Macro) "), .0)] | ||||
|     MacroError(#[from] mir::pass::Error<macros::ErrorKind>), | ||||
|     #[error("{}{}", label("(Generics) "), .0)] | ||||
|     GenericsError(#[from] mir::pass::Error<generics::ErrorKind>), | ||||
|     #[error("{}{}", label("(Codegen) "), .0)] | ||||
|     CodegenError(#[from] codegen::ErrorKind), | ||||
| } | ||||
| @ -62,6 +64,7 @@ impl ErrorKind { | ||||
|                 codegen::ErrorKind::Null => Default::default(), | ||||
|             }, | ||||
|             ErrorKind::MacroError(error) => error.metadata, | ||||
|             ErrorKind::GenericsError(error) => error.metadata, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -74,6 +77,7 @@ impl ErrorKind { | ||||
|             ErrorKind::LinkerError(_) => "linker", | ||||
|             ErrorKind::MacroError(_) => "macro-pass", | ||||
|             ErrorKind::CodegenError(_) => "codegen", | ||||
|             ErrorKind::GenericsError(_) => "generics", | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -70,6 +70,7 @@ use reid_lib::{compile::CompileOutput, Context}; | ||||
| use crate::{ | ||||
|     ast::TopLevelStatement, | ||||
|     mir::{ | ||||
|         generics::GenericsPass, | ||||
|         macros::{form_macros, MacroModule, MacroPass}, | ||||
|         SourceModuleId, | ||||
|     }, | ||||
| @ -177,6 +178,24 @@ pub fn perform_all_passes<'map>( | ||||
|         is_lib: true, | ||||
|     })?; | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     log::trace!("{:-^100}", "LINKER OUTPUT"); | ||||
|     #[cfg(debug_assertions)] | ||||
|     log::trace!("{:#}", &context); | ||||
|     #[cfg(debug_assertions)] | ||||
|     log::trace!("{:#?}", &state); | ||||
| 
 | ||||
|     if !state.errors.is_empty() { | ||||
|         return Err(ReidError::from_kind( | ||||
|             state.errors.iter().map(|e| e.clone().into()).collect(), | ||||
|             module_map.clone(), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     let state = context.pass(&mut GenericsPass { | ||||
|         function_map: HashMap::new(), | ||||
|     })?; | ||||
| 
 | ||||
|     for module in &mut context.modules { | ||||
|         for intrinsic in form_intrinsics() { | ||||
|             module.1.functions.insert(0, intrinsic); | ||||
| @ -184,7 +203,7 @@ pub fn perform_all_passes<'map>( | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     log::trace!("{:-^100}", "LINKER OUTPUT"); | ||||
|     log::trace!("{:-^100}", "GENERICS OUTPUT"); | ||||
|     #[cfg(debug_assertions)] | ||||
|     log::trace!("{:#}", &context); | ||||
|     #[cfg(debug_assertions)] | ||||
|  | ||||
| @ -157,9 +157,14 @@ impl Display for FunctionDefinition { | ||||
|         } | ||||
|         write!( | ||||
|             f, | ||||
|             "{}fn {}({}) -> {:#} ", | ||||
|             "{}fn {}<{}>({}) -> {:#} ", | ||||
|             if self.is_pub { "pub " } else { "" }, | ||||
|             self.name, | ||||
|             self.generics | ||||
|                 .iter() | ||||
|                 .map(|(n, t)| format!("{n} = {:?}", t)) | ||||
|                 .collect::<Vec<_>>() | ||||
|                 .join(", "), | ||||
|             self.parameters | ||||
|                 .iter() | ||||
|                 .map(|FunctionParam { name, ty, .. }| format!("{}: {:#}", name, ty)) | ||||
| @ -489,12 +494,14 @@ impl Display for VagueType { | ||||
|                 VagueType::Integer => write!(f, "Number"), | ||||
|                 VagueType::TypeRef(id) => write!(f, "TypeRef({0})", id), | ||||
|                 VagueType::Decimal => write!(f, "Decimal"), | ||||
|                 VagueType::Named(name) => write!(f, "Named<{name}>"), | ||||
|             } | ||||
|         } else { | ||||
|             match self { | ||||
|                 VagueType::Unknown => write!(f, "{{unknown}}"), | ||||
|                 VagueType::Integer => write!(f, "Number"), | ||||
|                 VagueType::TypeRef(_) => write!(f, "{{unknown}}"), | ||||
|                 VagueType::Named(name) => write!(f, "{name}"), | ||||
|                 VagueType::Decimal => write!(f, "Decimal"), | ||||
|             } | ||||
|         } | ||||
|  | ||||
							
								
								
									
										296
									
								
								reid/src/mir/generics.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								reid/src/mir/generics.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,296 @@ | ||||
| use std::{collections::HashMap, path::PathBuf}; | ||||
| 
 | ||||
| use log::Metadata; | ||||
| 
 | ||||
| use crate::mir::{ | ||||
|     self, generics, CustomTypeKey, FunctionCall, FunctionDefinition, FunctionParam, GlobalKind, GlobalValue, | ||||
|     IfExpression, Literal, Module, SourceModuleId, TypeKind, WhileStatement, | ||||
| }; | ||||
| 
 | ||||
| use super::pass::{Pass, PassResult, PassState}; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum ErrorKind { | ||||
|     #[error("Should never be encountered!")] | ||||
|     Null, | ||||
|     #[error("Expected {0} type-arguments, got {1}!")] | ||||
|     InvalidNumberTypeArguments(u32, u32), | ||||
| } | ||||
| 
 | ||||
| type Calls = Vec<(Vec<TypeKind>, mir::Metadata)>; | ||||
| 
 | ||||
| pub struct GenericsPass { | ||||
|     pub function_map: HashMap<SourceModuleId, Functions>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct Functions { | ||||
|     calls: HashMap<String, Calls>, | ||||
|     assoc_calls: HashMap<(TypeKind, String), Calls>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Default, Clone)] | ||||
| pub struct GenericsPassData { | ||||
|     generic_types: HashMap<String, TypeKind>, | ||||
| } | ||||
| 
 | ||||
| type GenericsPassState<'map, 'st, 'sc> = PassState<'st, 'sc, GenericsPassData, ErrorKind>; | ||||
| 
 | ||||
| impl Pass for GenericsPass { | ||||
|     type Data = GenericsPassData; | ||||
|     type TError = ErrorKind; | ||||
| 
 | ||||
|     fn context(&mut self, context: &mut mir::Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult { | ||||
|         let mut function_map = HashMap::new(); | ||||
|         for module in &context.modules { | ||||
|             function_map.insert( | ||||
|                 module.0.clone(), | ||||
|                 Functions { | ||||
|                     calls: HashMap::new(), | ||||
|                     assoc_calls: HashMap::new(), | ||||
|                 }, | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         for module in &mut context.modules { | ||||
|             let mut calls = HashMap::new(); | ||||
|             let mut assoc_calls = HashMap::new(); | ||||
|             for function in &mut module.1.associated_functions { | ||||
|                 match &mut function.1.kind { | ||||
|                     mir::FunctionDefinitionKind::Local(block, _) => block.find_calls(&mut calls, &mut assoc_calls), | ||||
|                     mir::FunctionDefinitionKind::Extern(_) => {} | ||||
|                     mir::FunctionDefinitionKind::Intrinsic(_) => {} | ||||
|                 } | ||||
|             } | ||||
|             for function in &mut module.1.functions { | ||||
|                 match &mut function.kind { | ||||
|                     mir::FunctionDefinitionKind::Local(block, _) => block.find_calls(&mut calls, &mut assoc_calls), | ||||
|                     mir::FunctionDefinitionKind::Extern(_) => {} | ||||
|                     mir::FunctionDefinitionKind::Intrinsic(_) => {} | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             for function in &module.1.associated_functions { | ||||
|                 if let Some(source) = function.1.source { | ||||
|                     let key = (function.0.clone(), function.1.name.clone()); | ||||
|                     function_map | ||||
|                         .get_mut(&source) | ||||
|                         .unwrap() | ||||
|                         .assoc_calls | ||||
|                         .insert(key.clone(), assoc_calls.get(&key).cloned().unwrap_or_default()); | ||||
|                 } | ||||
|             } | ||||
|             for function in &module.1.functions { | ||||
|                 if let Some(source) = function.source { | ||||
|                     function_map.get_mut(&source).unwrap().calls.insert( | ||||
|                         function.name.clone(), | ||||
|                         calls.get(&function.name).cloned().unwrap_or_default(), | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         self.function_map = function_map; | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn module(&mut self, module: &mut mir::Module, mut state: PassState<Self::Data, Self::TError>) -> PassResult { | ||||
|         for function in module.functions.drain(..).collect::<Vec<_>>() { | ||||
|             if let Some(source) = function.source { | ||||
|                 let functions = self.function_map.get(&source).unwrap(); | ||||
|                 let calls = functions.calls.get(&function.name).unwrap(); | ||||
| 
 | ||||
|                 for call in calls { | ||||
|                     if call.0.len() != function.generics.len() { | ||||
|                         state.note_errors( | ||||
|                             &vec![ErrorKind::InvalidNumberTypeArguments( | ||||
|                                 function.generics.len() as u32, | ||||
|                                 call.0.len() as u32, | ||||
|                             )], | ||||
|                             call.1, | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if function.generics.len() > 0 { | ||||
|                     for call in calls { | ||||
|                         if let Some(clone) = function.try_clone() { | ||||
|                             let generics = function | ||||
|                                 .generics | ||||
|                                 .iter() | ||||
|                                 .zip(call.0.clone()) | ||||
|                                 .map(|((n, _), t)| (n.clone(), t.clone())) | ||||
|                                 .collect(); | ||||
|                             module.functions.push(FunctionDefinition { | ||||
|                                 name: name_fmt(function.name.clone(), call.0.clone()), | ||||
|                                 return_type: function.return_type.replace_generic(&generics), | ||||
|                                 parameters: function | ||||
|                                     .parameters | ||||
|                                     .iter() | ||||
|                                     .map(|p| FunctionParam { | ||||
|                                         ty: p.ty.replace_generic(&generics), | ||||
|                                         ..p.clone() | ||||
|                                     }) | ||||
|                                     .collect(), | ||||
|                                 generics, | ||||
|                                 ..clone | ||||
|                             }); | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     module.functions.push(function); | ||||
|                 } | ||||
|             } else { | ||||
|                 module.functions.push(function); | ||||
|             } | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn function( | ||||
|         &mut self, | ||||
|         func: &mut FunctionDefinition, | ||||
|         mut state: PassState<Self::Data, Self::TError>, | ||||
|     ) -> PassResult { | ||||
|         for (name, ty) in &func.generics { | ||||
|             state.scope.data.generic_types.insert(name.clone(), ty.clone()); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn stmt(&mut self, stmt: &mut mir::Statement, mut state: PassState<Self::Data, Self::TError>) -> PassResult { | ||||
|         match &mut stmt.0 { | ||||
|             mir::StmtKind::Let(var_ref, _, _) => match var_ref.0.clone() { | ||||
|                 TypeKind::CustomType(custom_type_key) => { | ||||
|                     if let Some(ty) = state.scope.data.generic_types.get(&custom_type_key.0) { | ||||
|                         var_ref.0 = ty.clone(); | ||||
|                     } | ||||
|                 } | ||||
|                 _ => {} | ||||
|             }, | ||||
|             _ => {} | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl mir::Block { | ||||
|     fn find_calls(&mut self, calls: &mut HashMap<String, Calls>, assoc_calls: &mut HashMap<(TypeKind, String), Calls>) { | ||||
|         for statement in &mut self.statements { | ||||
|             statement.find_calls(calls, assoc_calls); | ||||
|         } | ||||
|         if let Some((_, Some(e))) = &mut self.return_expression { | ||||
|             e.find_calls(calls, assoc_calls); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl mir::Statement { | ||||
|     fn find_calls(&mut self, calls: &mut HashMap<String, Calls>, assoc_calls: &mut HashMap<(TypeKind, String), Calls>) { | ||||
|         match &mut self.0 { | ||||
|             mir::StmtKind::Let(_, _, expression) => expression.find_calls(calls, assoc_calls), | ||||
|             mir::StmtKind::Set(expression, expression1) => { | ||||
|                 expression.find_calls(calls, assoc_calls); | ||||
|                 expression1.find_calls(calls, assoc_calls); | ||||
|             } | ||||
|             mir::StmtKind::Import(_) => {} | ||||
|             mir::StmtKind::Expression(expression) => expression.find_calls(calls, assoc_calls), | ||||
|             mir::StmtKind::While(WhileStatement { condition, block, .. }) => { | ||||
|                 condition.find_calls(calls, assoc_calls); | ||||
|                 block.find_calls(calls, assoc_calls); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl mir::Expression { | ||||
|     fn find_calls(&mut self, calls: &mut HashMap<String, Calls>, assoc_calls: &mut HashMap<(TypeKind, String), Calls>) { | ||||
|         match &mut self.0 { | ||||
|             mir::ExprKind::Variable(_) => {} | ||||
|             mir::ExprKind::Indexed(expression, _, expression1) => { | ||||
|                 expression.find_calls(calls, assoc_calls); | ||||
|                 expression1.find_calls(calls, assoc_calls); | ||||
|             } | ||||
|             mir::ExprKind::Accessed(expression, _, _, _) => { | ||||
|                 expression.find_calls(calls, assoc_calls); | ||||
|             } | ||||
|             mir::ExprKind::Array(expressions) => { | ||||
|                 for expression in expressions { | ||||
|                     expression.find_calls(calls, assoc_calls); | ||||
|                 } | ||||
|             } | ||||
|             mir::ExprKind::Struct(_, items) => { | ||||
|                 for item in items { | ||||
|                     item.1.find_calls(calls, assoc_calls); | ||||
|                 } | ||||
|             } | ||||
|             mir::ExprKind::Literal(_) => {} | ||||
|             mir::ExprKind::BinOp(_, lhs, rhs, _) => { | ||||
|                 lhs.find_calls(calls, assoc_calls); | ||||
|                 rhs.find_calls(calls, assoc_calls); | ||||
|             } | ||||
|             mir::ExprKind::FunctionCall(function_call) => { | ||||
|                 if let Some(calls) = calls.get_mut(&function_call.name) { | ||||
|                     calls.push((function_call.generics.clone(), self.1)); | ||||
|                 } else { | ||||
|                     calls.insert( | ||||
|                         function_call.name.clone(), | ||||
|                         vec![(function_call.generics.clone(), self.1)], | ||||
|                     ); | ||||
|                 } | ||||
|                 if function_call.generics.len() > 0 { | ||||
|                     function_call.name = name_fmt(function_call.name.clone(), function_call.generics.clone()) | ||||
|                 } | ||||
|             } | ||||
|             mir::ExprKind::AssociatedFunctionCall(ty, function_call) => { | ||||
|                 if let Some(calls) = assoc_calls.get_mut(&(ty.clone(), function_call.name.clone())) { | ||||
|                     calls.push((function_call.generics.clone(), self.1)); | ||||
|                 } else { | ||||
|                     assoc_calls.insert( | ||||
|                         (ty.clone(), function_call.name.clone()), | ||||
|                         vec![(function_call.generics.clone(), self.1)], | ||||
|                     ); | ||||
|                 } | ||||
|                 if function_call.generics.len() > 0 { | ||||
|                     function_call.name = name_fmt(function_call.name.clone(), function_call.generics.clone()) | ||||
|                 } | ||||
|             } | ||||
|             mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => { | ||||
|                 cond.find_calls(calls, assoc_calls); | ||||
|                 then_e.find_calls(calls, assoc_calls); | ||||
|                 if let Some(else_e) = else_e.as_mut() { | ||||
|                     else_e.find_calls(calls, assoc_calls); | ||||
|                 } | ||||
|             } | ||||
|             mir::ExprKind::Block(block) => block.find_calls(calls, assoc_calls), | ||||
|             mir::ExprKind::Borrow(expression, _) => expression.find_calls(calls, assoc_calls), | ||||
|             mir::ExprKind::Deref(expression) => expression.find_calls(calls, assoc_calls), | ||||
|             mir::ExprKind::CastTo(expression, _) => expression.find_calls(calls, assoc_calls), | ||||
|             mir::ExprKind::GlobalRef(_, _) => {} | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn name_fmt(name: String, generics: Vec<TypeKind>) -> String { | ||||
|     format!( | ||||
|         "{}.{}", | ||||
|         name, | ||||
|         generics.iter().map(|t| t.to_string()).collect::<Vec<_>>().join(".") | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| impl TypeKind { | ||||
|     fn replace_generic(&self, generics: &Vec<(String, TypeKind)>) -> TypeKind { | ||||
|         match self { | ||||
|             TypeKind::CustomType(CustomTypeKey(name, _)) => { | ||||
|                 if let Some((_, inner)) = generics.iter().find(|(n, _)| n == name) { | ||||
|                     inner.clone() | ||||
|                 } else { | ||||
|                     self.clone() | ||||
|                 } | ||||
|             } | ||||
|             _ => self.clone(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -171,6 +171,7 @@ impl TypeKind { | ||||
|                 VagueType::Integer => TypeCategory::Integer, | ||||
|                 VagueType::Decimal => TypeCategory::Real, | ||||
|                 VagueType::TypeRef(_) => TypeCategory::TypeRef, | ||||
|                 VagueType::Named(_) => TypeCategory::Other, | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -311,6 +311,7 @@ impl<'map> Pass for LinkerPass<'map> { | ||||
| 
 | ||||
|                 importer_module.functions.push(FunctionDefinition { | ||||
|                     name: function.name.clone(), | ||||
|                     generics: function.generics.clone(), | ||||
|                     documentation: function.documentation.clone(), | ||||
|                     linkage_name: None, | ||||
|                     is_pub: false, | ||||
| @ -460,6 +461,7 @@ impl<'map> Pass for LinkerPass<'map> { | ||||
|                             FunctionDefinition { | ||||
|                                 name: func_name.clone(), | ||||
|                                 documentation: func.documentation.clone(), | ||||
|                                 generics: func.generics.clone(), | ||||
|                                 linkage_name: Some(format!("{}::{}", ty, func_name)), | ||||
|                                 is_pub: false, | ||||
|                                 is_imported: false, | ||||
|  | ||||
| @ -11,6 +11,7 @@ use crate::{ | ||||
| }; | ||||
| 
 | ||||
| mod fmt; | ||||
| pub mod generics; | ||||
| pub mod implement; | ||||
| pub mod linker; | ||||
| pub mod macros; | ||||
| @ -135,13 +136,14 @@ pub enum TypeKind { | ||||
|     Vague(VagueType), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||||
| pub enum VagueType { | ||||
|     Unknown, | ||||
|     /// Some integer value (e.g. 5)
 | ||||
|     Integer, | ||||
|     /// Some decimal fractional value (e.g. 1.5)
 | ||||
|     Decimal, | ||||
|     Named(String), | ||||
|     TypeRef(usize), | ||||
| } | ||||
| 
 | ||||
| @ -164,7 +166,7 @@ impl StructType { | ||||
| impl TypeKind { | ||||
|     pub fn known(&self) -> Result<TypeKind, VagueType> { | ||||
|         if let TypeKind::Vague(vague) = self { | ||||
|             Err(*vague) | ||||
|             Err(vague.clone()) | ||||
|         } else { | ||||
|             Ok(self.clone()) | ||||
|         } | ||||
| @ -309,6 +311,7 @@ pub struct IfExpression(pub Box<Expression>, pub Box<Expression>, pub Box<Option | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct FunctionCall { | ||||
|     pub name: String, | ||||
|     pub generics: Vec<TypeKind>, | ||||
|     pub return_type: TypeKind, | ||||
|     pub parameters: Vec<Expression>, | ||||
|     pub is_macro: bool, | ||||
| @ -320,6 +323,7 @@ pub struct FunctionDefinition { | ||||
|     pub name: String, | ||||
|     pub documentation: Option<String>, | ||||
|     pub linkage_name: Option<String>, | ||||
|     pub generics: Vec<(String, TypeKind)>, | ||||
|     /// Whether this function is visible to outside modules
 | ||||
|     pub is_pub: bool, | ||||
|     /// Whether this module is from an external module, and has been imported
 | ||||
| @ -331,6 +335,40 @@ pub struct FunctionDefinition { | ||||
|     pub signature_meta: Metadata, | ||||
| } | ||||
| 
 | ||||
| impl FunctionDefinition { | ||||
|     pub fn try_clone(&self) -> Option<FunctionDefinition> { | ||||
|         match &self.kind { | ||||
|             FunctionDefinitionKind::Local(block, metadata) => Some(FunctionDefinition { | ||||
|                 name: self.name.clone(), | ||||
|                 documentation: self.documentation.clone(), | ||||
|                 linkage_name: self.linkage_name.clone(), | ||||
|                 generics: self.generics.clone(), | ||||
|                 is_pub: self.is_pub.clone(), | ||||
|                 is_imported: self.is_imported.clone(), | ||||
|                 return_type: self.return_type.clone(), | ||||
|                 parameters: self.parameters.clone(), | ||||
|                 kind: FunctionDefinitionKind::Local(block.clone(), metadata.clone()), | ||||
|                 source: self.source.clone(), | ||||
|                 signature_meta: self.signature_meta.clone(), | ||||
|             }), | ||||
|             FunctionDefinitionKind::Extern(e) => Some(FunctionDefinition { | ||||
|                 name: self.name.clone(), | ||||
|                 documentation: self.documentation.clone(), | ||||
|                 linkage_name: self.linkage_name.clone(), | ||||
|                 generics: self.generics.clone(), | ||||
|                 is_pub: self.is_pub.clone(), | ||||
|                 is_imported: self.is_imported.clone(), | ||||
|                 return_type: self.return_type.clone(), | ||||
|                 parameters: self.parameters.clone(), | ||||
|                 kind: FunctionDefinitionKind::Extern(*e), | ||||
|                 source: self.source.clone(), | ||||
|                 signature_meta: self.signature_meta.clone(), | ||||
|             }), | ||||
|             FunctionDefinitionKind::Intrinsic(intrinsic_function) => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, PartialOrd)] | ||||
| pub struct FunctionParam { | ||||
|     pub name: String, | ||||
|  | ||||
| @ -290,10 +290,11 @@ impl TypeKind { | ||||
|     pub(super) fn or_default(&self) -> Result<TypeKind, ErrorKind> { | ||||
|         Ok(match self { | ||||
|             TypeKind::Vague(vague_type) => match &vague_type { | ||||
|                 Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type))?, | ||||
|                 Vague::Unknown => Err(ErrorKind::TypeIsVague(vague_type.clone()))?, | ||||
|                 Vague::Integer => TypeKind::I32, | ||||
|                 Vague::TypeRef(_) => panic!("Hinted default!"), | ||||
|                 VagueType::Decimal => TypeKind::F32, | ||||
|                 VagueType::Named(_) => panic!("Defaulted unknown named!"), | ||||
|             }, | ||||
|             TypeKind::Array(type_kind, len) => TypeKind::Array(Box::new(type_kind.or_default()?), *len), | ||||
|             TypeKind::Borrow(type_kind, mutable) => TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable), | ||||
| @ -339,7 +340,7 @@ impl TypeKind { | ||||
|             TypeKind::Borrow(type_kind, _) => type_kind.is_known(state), | ||||
|             TypeKind::UserPtr(type_kind) => type_kind.is_known(state), | ||||
|             TypeKind::CodegenPtr(type_kind) => type_kind.is_known(state), | ||||
|             TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)), | ||||
|             TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(vague_type.clone())), | ||||
|             _ => Ok(()), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -368,6 +368,7 @@ impl<'outer> ScopeTypeRefs<'outer> { | ||||
|                     self.narrow_to_type(&typeref, &self.try_default_deep(&typeref.resolve_deep()?)?)? | ||||
|                         .resolve_deep()? | ||||
|                 } | ||||
|                 VagueType::Named(_) => ty.clone(), | ||||
|             }, | ||||
|             _ => ty.clone(), | ||||
|         }) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user