use crate::ast::RawAST;
use crate::core::Environment;
use crate::error::Error;
use crate::eval::{Context, Eval, Evaluated};
use crate::expand::Expand;
use crate::resolve::{Resolve, Scope};
use crate::substitution::AliasSubstitutionVisitor;
use crate::util::deprecation::DeprecationServiceScope;
use crate::util::log::debug;
use proc_macro2::TokenStream;
use quote::quote;
use std::collections::HashMap;
use std::rc::Rc;
use syn::visit_mut::VisitMut;
pub struct Interpreter {
environment: Rc<Environment>,
deprecation_service: DeprecationServiceScope,
}
impl Interpreter {
pub fn new(environment: Rc<Environment>, deprecation_service: DeprecationServiceScope) -> Self {
Interpreter {
environment,
deprecation_service,
}
}
pub fn execute(self, args: RawAST) -> Result<TokenStream, Error> {
debug!("Executing interpreter with arguments: {:?}", args);
let expanded = args.expand()?;
let mut out = vec![];
for inv in expanded.invocations {
let mut scope = Scope::default();
inv.spec()
.resolve(self.environment.as_ref(), &mut scope, None)?;
let mut context = Context::new(scope.metadata_rc());
let evaluated = inv.spec().eval(&self.environment, &mut context)?;
let Evaluated::Bindings(bindings_map) = evaluated else {
unreachable!()
};
let mut substitutions = HashMap::new();
for (alias, value) in bindings_map.iter() {
let Evaluated::Value(value) = value else {
unreachable!()
};
substitutions.insert(alias.ident().to_string(), value.clone());
}
let mut block = inv.block().clone();
let mut visitor = AliasSubstitutionVisitor::new(substitutions);
visitor.visit_block_mut(&mut block);
if let Some(err) = visitor.error() {
return Err(err.clone());
}
self.deprecation_service.emit(&mut block);
let content = &block.stmts;
out.push(quote! { #(#content)* });
}
Ok(quote! { #(#out)* })
}
}