use crate::*;
use leo_ast::NetworkName;
use leo_errors::{BufferEmitter, Handler};
use leo_parser::parse_ast;
use leo_span::{create_session_if_not_set_then, source_map::FileName, with_session_globals};
use serial_test::serial;
use std::rc::Rc;
macro_rules! compiler_passes {
($macro:ident) => {
$macro! {
(common_subexpression_elimination_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(CommonSubexpressionEliminating, ())
]),
(const_prop_unroll_and_morphing_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(ConstPropUnrollAndMorphing, (TypeCheckingInput::new(NetworkName::TestnetV0)))
]),
(destructuring_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(Destructuring, ())
]),
(dead_code_elimination_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(DeadCodeEliminating, ())
]),
(flattening_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(Flattening, ())
]),
(function_inlining_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(FunctionInlining, ())
]),
(option_lowering_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(OptionLowering, (TypeCheckingInput::new(NetworkName::TestnetV0)))
]),
(processing_async_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(ProcessingAsync, (TypeCheckingInput::new(NetworkName::TestnetV0)))
]),
(processing_script_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(ProcessingScript, ())
]),
(ssa_forming_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(SsaForming, (SsaFormingInput { rename_defs: true }))
]),
(storage_lowering_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(StorageLowering, (TypeCheckingInput::new(NetworkName::TestnetV0)))
]),
(write_transforming_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(WriteTransforming, ())
]),
(remove_unreachable_runner, [
(RemoveUnreachable, ())
]),
(ssa_const_propagation_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
(SsaForming, (SsaFormingInput { rename_defs: true })),
(SsaConstPropagation, ()),
]),
(disambiguate_runner, [
(GlobalVarsCollection, ()),
(PathResolution, ()),
(GlobalItemsCollection, ()),
(TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
(Disambiguate, ()),
]),
}
};
}
macro_rules! make_runner {
($runner_name:ident, [$(($pass:ident, $input:expr)),* $(,)?]) => {
fn $runner_name(source: &str) -> String {
let buf = BufferEmitter::new();
let handler = Handler::new(buf.clone());
let node_builder = Rc::new(leo_ast::NodeBuilder::default());
create_session_if_not_set_then(|_| {
let mut state = CompilerState { handler: handler.clone(), node_builder: Rc::clone(&node_builder), ..Default::default() };
state.ast = match handler.extend_if_error(parse_ast(
handler.clone(),
&state.node_builder,
&with_session_globals(|s| s.source_map.new_source(source, FileName::Custom("test".into()))),
&[],
NetworkName::TestnetV0,
)) {
Ok(ast) => ast,
Err(()) => return format!("{}{}", buf.extract_errs(), buf.extract_warnings()),
};
$(
if handler.extend_if_error($pass::do_pass($input, &mut state)).is_err() {
return format!("{}{}", buf.extract_errs(), buf.extract_warnings());
}
)*
format!("{}{}", buf.extract_warnings(), state.ast.ast)
})
}
};
}
macro_rules! make_all_runners {
($(($runner:ident, $passes:tt)),* $(,)?) => {
$(
make_runner!($runner, $passes);
)*
};
}
compiler_passes!(make_all_runners);
macro_rules! make_all_tests {
($(($runner:ident, [$(($pass:ident, $input:tt)),* $(,)?])),* $(,)?) => {
$(
paste::paste! {
#[test]
#[serial]
fn [<$runner _test>]() {
make_all_tests_inner!($runner, [$(($pass, $input)),*]);
}
}
)*
};
}
macro_rules! make_all_tests_inner {
($runner:ident, [($pass:ident, $input:tt)]) => {
paste::paste! {
leo_test_framework::run_tests(
concat!("passes/", stringify!([<$pass:snake>])),
$runner,
);
}
};
($runner:ident, [($pass:ident, $input:tt), $(($rest_pass:ident, $rest_input:tt)),+ $(,)?]) => {
make_all_tests_inner!($runner, [$(($rest_pass, $rest_input)),+]);
};
}
compiler_passes!(make_all_tests);