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