use std::any::Any;
use std::error::Error as StdError;
use std::mem;
use std::sync::{Arc, RwLock};
use futures::{stream, Future, Stream};
use crate::base::ast::{self, Expr, MutVisitor, SpannedExpr, ValueBindings};
use crate::base::error::Errors as BaseErrors;
use crate::base::fnv::FnvMap;
use crate::base::pos;
use crate::base::pos::{BytePos, Spanned};
use crate::base::symbol::{Symbol, Symbols};
use crate::thread::Thread;
pub type Error = Box<StdError + Send + Sync>;
pub type SpannedError = Spanned<Error, BytePos>;
pub type Errors = BaseErrors<SpannedError>;
pub type MacroFuture = Box<Future<Item = SpannedExpr<Symbol>, Error = Error> + Send>;
pub trait Macro: ::mopa::Any + Send + Sync {
fn expand(&self, env: &mut MacroExpander, args: Vec<SpannedExpr<Symbol>>) -> MacroFuture;
}
mopafy!(Macro);
impl<F: ::mopa::Any + Clone + Send + Sync> Macro for F
where
F: Fn(
&mut MacroExpander,
Vec<SpannedExpr<Symbol>>,
) -> Box<Future<Item = SpannedExpr<Symbol>, Error = Error> + Send>,
{
fn expand(
&self,
env: &mut MacroExpander,
args: Vec<SpannedExpr<Symbol>>,
) -> Box<Future<Item = SpannedExpr<Symbol>, Error = Error> + Send> {
self(env, args)
}
}
#[derive(Default)]
pub struct MacroEnv {
macros: RwLock<FnvMap<String, Arc<Macro>>>,
}
impl MacroEnv {
pub fn new() -> MacroEnv {
MacroEnv {
macros: RwLock::new(FnvMap::default()),
}
}
pub fn insert<M>(&self, name: String, mac: M)
where
M: Macro + 'static,
{
self.macros.write().unwrap().insert(name, Arc::new(mac));
}
pub fn get(&self, name: &str) -> Option<Arc<Macro>> {
self.macros.read().unwrap().get(name).cloned()
}
pub fn run(
&self,
vm: &Thread,
symbols: &mut Symbols,
expr: &mut SpannedExpr<Symbol>,
) -> Result<(), Errors> {
let mut expander = MacroExpander::new(vm);
expander.run(symbols, expr);
expander.finish()
}
}
pub struct MacroExpander<'a> {
pub state: FnvMap<String, Box<Any>>,
pub vm: &'a Thread,
pub errors: Errors,
pub error_in_expr: bool,
macros: &'a MacroEnv,
}
impl<'a> MacroExpander<'a> {
pub fn new(vm: &'a Thread) -> MacroExpander<'a> {
MacroExpander {
vm: vm,
state: FnvMap::default(),
macros: vm.get_macros(),
error_in_expr: false,
errors: Errors::new(),
}
}
pub fn finish(self) -> Result<(), Errors> {
if self.error_in_expr || self.errors.has_errors() {
Err(self.errors)
} else {
Ok(())
}
}
pub fn run(&mut self, symbols: &mut Symbols, expr: &mut SpannedExpr<Symbol>) {
{
let exprs = {
let mut visitor = MacroVisitor {
expander: self,
symbols,
exprs: Vec::new(),
};
visitor.visit_expr(expr);
visitor.exprs
};
let _ = stream::futures_ordered(exprs.into_iter().map(move |(expr, future)| {
future.then(move |result| -> Result<_, ()> {
match result {
Ok(mut replacement) => {
replacement.span = expr.span;
replace_expr(expr, replacement);
Ok(None)
}
Err(err) => {
let expr_span = expr.span;
replace_expr(expr, pos::spanned(expr_span, Expr::Error(None)));
Ok(Some(pos::spanned(expr.span, err)))
}
}
})
}))
.for_each(|err| -> Result<(), ()> {
if let Some(err) = err {
self.errors.push(err);
}
Ok(())
})
.wait();
}
if self.errors.has_errors() {
info!("Macro errors: {}", self.errors);
}
}
}
fn replace_expr(expr: &mut SpannedExpr<Symbol>, new: SpannedExpr<Symbol>) {
let expr_span = expr.span;
let original = mem::replace(expr, pos::spanned(expr_span, Expr::Error(None)));
*expr = pos::spanned(
expr.span,
Expr::MacroExpansion {
original: Box::new(original),
replacement: Box::new(new),
},
);
}
struct MacroVisitor<'a: 'b, 'b, 'c> {
expander: &'b mut MacroExpander<'a>,
symbols: &'c mut Symbols,
exprs: Vec<(&'c mut SpannedExpr<Symbol>, MacroFuture)>,
}
impl<'a, 'b, 'c> MutVisitor<'c> for MacroVisitor<'a, 'b, 'c> {
type Ident = Symbol;
fn visit_expr(&mut self, expr: &'c mut SpannedExpr<Symbol>) {
let replacement = match expr.value {
Expr::App {
ref mut implicit_args,
func: ref mut id,
ref mut args,
} => match id.value {
Expr::Ident(ref id) if id.name.as_ref().ends_with('!') => {
if !implicit_args.is_empty() {
self.expander.errors.push(pos::spanned(
expr.span,
"Implicit arguments are not allowed on macros".into(),
));
}
let name = id.name.as_ref();
match self.expander.macros.get(&name[..name.len() - 1]) {
Some(m) => Some(m.expand(self.expander, args.clone())),
None => None,
}
}
_ => None,
},
Expr::TypeBindings(ref binds, ref mut body) => {
let generated_bindings = binds
.iter()
.flat_map(|bind| {
if let Some(derive) = bind
.metadata
.attributes
.iter()
.find(|attr| attr.name == "derive")
{
match crate::derive::generate(self.symbols, derive, bind) {
Ok(x) => x,
Err(err) => {
self.expander.errors.push(pos::spanned(bind.name.span, err));
Vec::new()
}
}
} else {
Vec::new()
}
})
.collect::<Vec<_>>();
if !generated_bindings.is_empty() {
let next_expr = mem::replace(body, Default::default());
body.value =
Expr::LetBindings(ValueBindings::Recursive(generated_bindings), next_expr);
}
None
}
_ => None,
};
if let Some(future) = replacement {
self.exprs.push((expr, future));
} else {
ast::walk_mut_expr(self, expr);
}
}
}