Implement macro-pass
This commit is contained in:
		
							parent
							
								
									33ed1fd813
								
							
						
					
					
						commit
						3d8f4bbd24
					
				| @ -3,7 +3,7 @@ use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValue, Instr, Type} | |||||||
| use crate::{ | use crate::{ | ||||||
|     codegen::{ErrorKind, StackValueKind}, |     codegen::{ErrorKind, StackValueKind}, | ||||||
|     mir::{ |     mir::{ | ||||||
|         self, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam, |         BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam, | ||||||
|         TypeKind, |         TypeKind, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
| @ -309,14 +309,6 @@ pub trait IntrinsicFunction: std::fmt::Debug { | |||||||
|     fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind>; |     fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub trait MacroFunction: std::fmt::Debug { |  | ||||||
|     fn generate<'ctx, 'a>( |  | ||||||
|         &self, |  | ||||||
|         scope: &mut Scope<'ctx, 'a>, |  | ||||||
|         params: &[mir::Literal], |  | ||||||
|     ) -> Result<mir::Expression, ErrorKind>; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| macro_rules! intrinsic_debug { | macro_rules! intrinsic_debug { | ||||||
|     ($kind:ty, $name:literal) => { |     ($kind:ty, $name:literal) => { | ||||||
|         impl<T> std::fmt::Debug for $kind |         impl<T> std::fmt::Debug for $kind | ||||||
|  | |||||||
| @ -7,10 +7,8 @@ use reid_lib::{ | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     codegen::intrinsics::MacroFunction, |  | ||||||
|     lexer::FullToken, |     lexer::FullToken, | ||||||
|     mir::{ |     mir::{ | ||||||
|         self, |  | ||||||
|         pass::{AssociatedFunctionKey, BinopKey}, |         pass::{AssociatedFunctionKey, BinopKey}, | ||||||
|         CustomTypeKey, FunctionParam, Metadata, SourceModuleId, TypeDefinition, TypeKind, |         CustomTypeKey, FunctionParam, Metadata, SourceModuleId, TypeDefinition, TypeKind, | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ use crate::{ | |||||||
|     ast::token_stream::{self, TokenRange}, |     ast::token_stream::{self, TokenRange}, | ||||||
|     codegen, |     codegen, | ||||||
|     lexer::{self, Cursor, FullToken, Position}, |     lexer::{self, Cursor, FullToken, Position}, | ||||||
|     mir::{self, pass, typecheck, Metadata, SourceModuleId}, |     mir::{self, macros, pass, typecheck, Metadata, SourceModuleId}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use crate::mir::typecheck::ErrorKind as TypecheckError; | use crate::mir::typecheck::ErrorKind as TypecheckError; | ||||||
| @ -33,6 +33,8 @@ pub enum ErrorKind { | |||||||
|     TypeInferenceError(#[source] mir::pass::Error<TypecheckError>), |     TypeInferenceError(#[source] mir::pass::Error<TypecheckError>), | ||||||
|     #[error("{}{}", label("(Linker) "), .0.kind)] |     #[error("{}{}", label("(Linker) "), .0.kind)] | ||||||
|     LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), |     LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), | ||||||
|  |     #[error("{}{}", label("(Macro) "), .0)] | ||||||
|  |     MacroError(#[from] mir::pass::Error<macros::ErrorKind>), | ||||||
|     #[error("{}{}", label("(Codegen) "), .0)] |     #[error("{}{}", label("(Codegen) "), .0)] | ||||||
|     CodegenError(#[from] codegen::ErrorKind), |     CodegenError(#[from] codegen::ErrorKind), | ||||||
| } | } | ||||||
| @ -58,6 +60,7 @@ impl ErrorKind { | |||||||
|             ErrorKind::CodegenError(error) => match error { |             ErrorKind::CodegenError(error) => match error { | ||||||
|                 codegen::ErrorKind::Null => Default::default(), |                 codegen::ErrorKind::Null => Default::default(), | ||||||
|             }, |             }, | ||||||
|  |             ErrorKind::MacroError(error) => error.metadata, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -56,7 +56,10 @@ use mir::{ | |||||||
| }; | }; | ||||||
| use reid_lib::{compile::CompileOutput, Context}; | use reid_lib::{compile::CompileOutput, Context}; | ||||||
| 
 | 
 | ||||||
| use crate::ast::TopLevelStatement; | use crate::{ | ||||||
|  |     ast::TopLevelStatement, | ||||||
|  |     mir::macros::{form_macros, MacroPass}, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| mod ast; | mod ast; | ||||||
| mod codegen; | mod codegen; | ||||||
| @ -133,6 +136,12 @@ pub fn perform_all_passes<'map>( | |||||||
|         is_lib: true, |         is_lib: true, | ||||||
|     })?; |     })?; | ||||||
| 
 | 
 | ||||||
|  |     for module in &mut context.modules { | ||||||
|  |         for intrinsic in form_intrinsics() { | ||||||
|  |             module.1.functions.insert(0, intrinsic); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #[cfg(debug_assertions)] |     #[cfg(debug_assertions)] | ||||||
|     println!("{:-^100}", "LINKER OUTPUT"); |     println!("{:-^100}", "LINKER OUTPUT"); | ||||||
|     #[cfg(debug_assertions)] |     #[cfg(debug_assertions)] | ||||||
| @ -140,6 +149,29 @@ pub fn perform_all_passes<'map>( | |||||||
|     #[cfg(debug_assertions)] |     #[cfg(debug_assertions)] | ||||||
|     dbg!(&state); |     dbg!(&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 MacroPass { macros: form_macros() })?; | ||||||
|  | 
 | ||||||
|  |     #[cfg(debug_assertions)] | ||||||
|  |     println!("{:-^100}", "MACRO OUTPUT"); | ||||||
|  |     #[cfg(debug_assertions)] | ||||||
|  |     println!("{:#}", &context); | ||||||
|  |     #[cfg(debug_assertions)] | ||||||
|  |     dbg!(&state); | ||||||
|  | 
 | ||||||
|  |     if !state.errors.is_empty() { | ||||||
|  |         return Err(ReidError::from_kind( | ||||||
|  |             state.errors.iter().map(|e| e.clone().into()).collect(), | ||||||
|  |             module_map.clone(), | ||||||
|  |         )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     let mut binops = BinopMap::default(); |     let mut binops = BinopMap::default(); | ||||||
|     for module in &mut context.modules { |     for module in &mut context.modules { | ||||||
|         for intrinsic in form_intrinsic_binops() { |         for intrinsic in form_intrinsic_binops() { | ||||||
| @ -160,19 +192,6 @@ pub fn perform_all_passes<'map>( | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for module in &mut context.modules { |  | ||||||
|         for intrinsic in form_intrinsics() { |  | ||||||
|             module.1.functions.insert(0, intrinsic); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if !state.errors.is_empty() { |  | ||||||
|         return Err(ReidError::from_kind( |  | ||||||
|             state.errors.iter().map(|e| e.clone().into()).collect(), |  | ||||||
|             module_map.clone(), |  | ||||||
|         )); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     let mut refs = TypeRefs::with_binops(binops); |     let mut refs = TypeRefs::with_binops(binops); | ||||||
| 
 | 
 | ||||||
|     let state = context.pass(&mut TypeInference { refs: &mut refs })?; |     let state = context.pass(&mut TypeInference { refs: &mut refs })?; | ||||||
|  | |||||||
| @ -1,19 +1,27 @@ | |||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| 
 | 
 | ||||||
| use crate::codegen::intrinsics::MacroFunction; | use crate::mir; | ||||||
| 
 | 
 | ||||||
| use super::pass::{Pass, PassResult, PassState}; | use super::pass::{Pass, PassResult, PassState}; | ||||||
| 
 | 
 | ||||||
|  | pub trait MacroFunction: std::fmt::Debug { | ||||||
|  |     fn generate<'ctx, 'a>(&self, params: &[mir::Literal]) -> Result<mir::ExprKind, ErrorKind>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||||
| pub enum ErrorKind { | pub enum ErrorKind { | ||||||
|     #[error("Should never be encountered!")] |     #[error("Should never be encountered!")] | ||||||
|     Null, |     Null, | ||||||
|  |     #[error("No such macro {0} defined")] | ||||||
|  |     NoSuchMacro(String), | ||||||
|  |     #[error("Macro arguments may only be literals")] | ||||||
|  |     InvalidMacroArgs, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Struct used to implement a type-checking pass that can be performed on the
 | /// Struct used to implement a type-checking pass that can be performed on the
 | ||||||
| /// MIR.
 | /// MIR.
 | ||||||
| pub struct MacroPass { | pub struct MacroPass { | ||||||
|     macros: HashMap<String, Box<dyn MacroFunction>>, |     pub(crate) macros: HashMap<String, Box<dyn MacroFunction>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type MacroPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; | type MacroPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; | ||||||
| @ -22,7 +30,59 @@ impl Pass for MacroPass { | |||||||
|     type Data = (); |     type Data = (); | ||||||
|     type TError = ErrorKind; |     type TError = ErrorKind; | ||||||
| 
 | 
 | ||||||
|     fn expr(&mut self, expr: &mut super::Expression, state: MacroPassState) -> PassResult { |     fn context(&mut self, _context: &mut mir::Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult { | ||||||
|  |         dbg!("hello??"); | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn expr(&mut self, expr: &mut super::Expression, mut state: MacroPassState) -> PassResult { | ||||||
|  |         dbg!("hello??"); | ||||||
|  |         match &expr.0 { | ||||||
|  |             super::ExprKind::FunctionCall(function_call) => { | ||||||
|  |                 if function_call.is_macro { | ||||||
|  |                     if let Some(existing_macro) = self.macros.get(&function_call.name) { | ||||||
|  |                         let mut literals = Vec::new(); | ||||||
|  |                         for param in &function_call.parameters { | ||||||
|  |                             match ¶m.0 { | ||||||
|  |                                 super::ExprKind::Literal(literal) => literals.push(literal.clone()), | ||||||
|  |                                 _ => state.note_errors(&vec![ErrorKind::InvalidMacroArgs], param.1), | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         *expr = state.or_else( | ||||||
|  |                             existing_macro | ||||||
|  |                                 .generate(&literals) | ||||||
|  |                                 .map(|kind| mir::Expression(kind, expr.1)), | ||||||
|  |                             expr.clone(), | ||||||
|  |                             expr.1, | ||||||
|  |                         ); | ||||||
|  |                     } else { | ||||||
|  |                         state.note_errors( | ||||||
|  |                             &vec![ErrorKind::NoSuchMacro(function_call.name.clone())], | ||||||
|  |                             function_call.meta, | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             _ => {} | ||||||
|  |         } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | pub fn form_macros() -> HashMap<String, Box<dyn MacroFunction>> { | ||||||
|  |     let mut macros: HashMap<String, Box<dyn MacroFunction>> = HashMap::new(); | ||||||
|  | 
 | ||||||
|  |     macros.insert("test_macro".to_owned(), Box::new(TestMacro)); | ||||||
|  | 
 | ||||||
|  |     macros | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct TestMacro; | ||||||
|  | impl MacroFunction for TestMacro { | ||||||
|  |     fn generate<'ctx, 'a>(&self, _: &[mir::Literal]) -> Result<mir::ExprKind, ErrorKind> { | ||||||
|  |         Ok(mir::ExprKind::Literal(mir::Literal::Vague(mir::VagueLiteral::Number( | ||||||
|  |             5, | ||||||
|  |         )))) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ use std::{collections::HashMap, path::PathBuf}; | |||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     ast::token_stream::TokenRange, |     ast::token_stream::TokenRange, | ||||||
|     codegen::intrinsics::{IntrinsicFunction, MacroFunction}, |     codegen::intrinsics::IntrinsicFunction, | ||||||
|     lexer::{FullToken, Position}, |     lexer::{FullToken, Position}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -503,6 +503,10 @@ impl Block { | |||||||
|             statement.pass(pass, state, &mut scope, mod_id)?; |             statement.pass(pass, state, &mut scope, mod_id)?; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if let Some((_, Some(return_expr))) = &mut self.return_expression { | ||||||
|  |             return_expr.pass(pass, state, &mut scope, mod_id)?; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         pass.block(self, PassState::from(state, &mut scope, Some(mod_id))) |         pass.block(self, PassState::from(state, &mut scope, Some(mod_id))) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user