diff --git a/reid/src/codegen/intrinsics.rs b/reid/src/codegen/intrinsics.rs index 407e79d..cb1cac3 100644 --- a/reid/src/codegen/intrinsics.rs +++ b/reid/src/codegen/intrinsics.rs @@ -3,7 +3,7 @@ use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValue, Instr, Type} use crate::{ codegen::{ErrorKind, StackValueKind}, mir::{ - self, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam, + BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam, TypeKind, }, }; @@ -309,14 +309,6 @@ pub trait IntrinsicFunction: std::fmt::Debug { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result; } -pub trait MacroFunction: std::fmt::Debug { - fn generate<'ctx, 'a>( - &self, - scope: &mut Scope<'ctx, 'a>, - params: &[mir::Literal], - ) -> Result; -} - macro_rules! intrinsic_debug { ($kind:ty, $name:literal) => { impl std::fmt::Debug for $kind diff --git a/reid/src/codegen/scope.rs b/reid/src/codegen/scope.rs index 409582e..19f20b5 100644 --- a/reid/src/codegen/scope.rs +++ b/reid/src/codegen/scope.rs @@ -7,10 +7,8 @@ use reid_lib::{ }; use crate::{ - codegen::intrinsics::MacroFunction, lexer::FullToken, mir::{ - self, pass::{AssociatedFunctionKey, BinopKey}, CustomTypeKey, FunctionParam, Metadata, SourceModuleId, TypeDefinition, TypeKind, }, diff --git a/reid/src/error_raporting.rs b/reid/src/error_raporting.rs index 40659a8..85a4f73 100644 --- a/reid/src/error_raporting.rs +++ b/reid/src/error_raporting.rs @@ -7,7 +7,7 @@ use crate::{ ast::token_stream::{self, TokenRange}, codegen, 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; @@ -33,6 +33,8 @@ pub enum ErrorKind { TypeInferenceError(#[source] mir::pass::Error), #[error("{}{}", label("(Linker) "), .0.kind)] LinkerError(#[from] mir::pass::Error), + #[error("{}{}", label("(Macro) "), .0)] + MacroError(#[from] mir::pass::Error), #[error("{}{}", label("(Codegen) "), .0)] CodegenError(#[from] codegen::ErrorKind), } @@ -58,6 +60,7 @@ impl ErrorKind { ErrorKind::CodegenError(error) => match error { codegen::ErrorKind::Null => Default::default(), }, + ErrorKind::MacroError(error) => error.metadata, } } } diff --git a/reid/src/lib.rs b/reid/src/lib.rs index c2e8081..e176e51 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -56,7 +56,10 @@ use mir::{ }; use reid_lib::{compile::CompileOutput, Context}; -use crate::ast::TopLevelStatement; +use crate::{ + ast::TopLevelStatement, + mir::macros::{form_macros, MacroPass}, +}; mod ast; mod codegen; @@ -133,6 +136,12 @@ pub fn perform_all_passes<'map>( is_lib: true, })?; + for module in &mut context.modules { + for intrinsic in form_intrinsics() { + module.1.functions.insert(0, intrinsic); + } + } + #[cfg(debug_assertions)] println!("{:-^100}", "LINKER OUTPUT"); #[cfg(debug_assertions)] @@ -140,6 +149,29 @@ pub fn perform_all_passes<'map>( #[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 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(); for module in &mut context.modules { 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 state = context.pass(&mut TypeInference { refs: &mut refs })?; diff --git a/reid/src/mir/macros.rs b/reid/src/mir/macros.rs index a1648be..796a537 100644 --- a/reid/src/mir/macros.rs +++ b/reid/src/mir/macros.rs @@ -1,19 +1,27 @@ use std::collections::HashMap; -use crate::codegen::intrinsics::MacroFunction; +use crate::mir; use super::pass::{Pass, PassResult, PassState}; +pub trait MacroFunction: std::fmt::Debug { + fn generate<'ctx, 'a>(&self, params: &[mir::Literal]) -> Result; +} + #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum ErrorKind { #[error("Should never be encountered!")] 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 /// MIR. pub struct MacroPass { - macros: HashMap>, + pub(crate) macros: HashMap>, } type MacroPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; @@ -22,7 +30,59 @@ impl Pass for MacroPass { type Data = (); 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) -> 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(()) } } + +pub fn form_macros() -> HashMap> { + let mut macros: HashMap> = 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 { + Ok(mir::ExprKind::Literal(mir::Literal::Vague(mir::VagueLiteral::Number( + 5, + )))) + } +} diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 12bef16..5a4f542 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -6,7 +6,7 @@ use std::{collections::HashMap, path::PathBuf}; use crate::{ ast::token_stream::TokenRange, - codegen::intrinsics::{IntrinsicFunction, MacroFunction}, + codegen::intrinsics::IntrinsicFunction, lexer::{FullToken, Position}, }; diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index d272f58..a3d2ff3 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -503,6 +503,10 @@ impl Block { 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))) } }