Implement macro-pass

This commit is contained in:
Sofia 2025-07-28 22:37:24 +03:00
parent 33ed1fd813
commit 3d8f4bbd24
7 changed files with 106 additions and 30 deletions

View File

@ -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

View File

@ -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,
}, },

View File

@ -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,
} }
} }
} }

View File

@ -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 })?;

View File

@ -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 &param.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,
))))
}
}

View File

@ -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},
}; };

View File

@ -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)))
} }
} }