/* * MRustC - Rust Compiler * - By John Hodge (Mutabah/thePowersGang) * * expand/mod.cpp * - Expand pass core code */ #include #include #include #include #include // ABI_RUST #define NEWNODE(_ty, ...) ::AST::ExprNodeP(new ::AST::ExprNode##_ty(__VA_ARGS__)) void Expand_TestHarness(::AST::Crate& crate) { // Create the following module: // ``` // mod `#test` { // extern crate std; // extern crate test; // fn main() { // self::test::test_main_static(&::`#test`::TESTS); // } // static TESTS: [test::TestDescAndFn; _] = [ // test::TestDescAndFn { desc: test::TestDesc { name: "foo", ignore: false, should_panic: test::ShouldPanic::No }, testfn: ::path::to::foo }, // ]; // } // ``` // ---- main function ---- auto main_fn = ::AST::Function { Span(), {}, ABI_RUST, false, false, false, TypeRef(TypeRef::TagUnit(), Span()), {} }; { auto call_node = NEWNODE(_CallPath, ::AST::Path("test", { ::AST::PathNode("test_main_static") }), ::make_vec1( NEWNODE(_UniOp, ::AST::ExprNode_UniOp::REF, NEWNODE(_NamedValue, ::AST::Path("", { ::AST::PathNode("test#"), ::AST::PathNode("TESTS") })) ) ) ); main_fn.set_code( mv$(call_node) ); } // ---- test list ---- ::std::vector< ::AST::ExprNodeP> test_nodes; for(const auto& test : crate.m_tests) { // HACK: Don't emit should_panic tests if( test.panic_type != ::AST::TestDesc::ShouldPanic::No ) continue ; ::AST::ExprNode_StructLiteral::t_values desc_vals; // `name: "foo",` desc_vals.push_back({ {}, "name", NEWNODE(_CallPath, ::AST::Path("test", { ::AST::PathNode("StaticTestName") }), ::make_vec1( NEWNODE(_String, test.name) ) ) }); // `ignore: false,` desc_vals.push_back({ {}, "ignore", NEWNODE(_Bool, test.ignore) }); // `should_panic: ShouldPanic::No,` { ::AST::ExprNodeP should_panic_val; switch(test.panic_type) { case ::AST::TestDesc::ShouldPanic::No: should_panic_val = NEWNODE(_NamedValue, ::AST::Path("test", { ::AST::PathNode("ShouldPanic"), ::AST::PathNode("No") })); break; case ::AST::TestDesc::ShouldPanic::Yes: should_panic_val = NEWNODE(_NamedValue, ::AST::Path("test", { ::AST::PathNode("ShouldPanic"), ::AST::PathNode("Yes") })); break; case ::AST::TestDesc::ShouldPanic::YesWithMessage: should_panic_val = NEWNODE(_CallPath, ::AST::Path("test", { ::AST::PathNode("ShouldPanic"), ::AST::PathNode("YesWithMessage") }), make_vec1( NEWNODE(_String, test.expected_panic_message) ) ); break; } desc_vals.push_back({ {}, "should_panic", mv$(should_panic_val) }); } if( TARGETVER_1_29 ) { // TODO: Get this from attributes desc_vals.push_back({ {}, "allow_fail", NEWNODE(_Bool, false) }); } auto desc_expr = NEWNODE(_StructLiteral, ::AST::Path("test", { ::AST::PathNode("TestDesc")}), nullptr, mv$(desc_vals)); ::AST::ExprNode_StructLiteral::t_values descandfn_vals; descandfn_vals.push_back({ {}, RcString::new_interned("desc"), mv$(desc_expr) }); auto test_type_var_name = test.is_benchmark ? "StaticBenchFn" : "StaticTestFn"; descandfn_vals.push_back({ {}, RcString::new_interned("testfn"), NEWNODE(_CallPath, ::AST::Path("test", { ::AST::PathNode(test_type_var_name) }), ::make_vec1( NEWNODE(_NamedValue, AST::Path(test.path)) ) ) }); test_nodes.push_back( NEWNODE(_StructLiteral, ::AST::Path("test", { ::AST::PathNode("TestDescAndFn")}), nullptr, mv$(descandfn_vals) ) ); } auto* tests_array = new ::AST::ExprNode_Array(mv$(test_nodes)); size_t test_count = tests_array->m_values.size(); auto tests_list = ::AST::Static { ::AST::Static::Class::STATIC, TypeRef(TypeRef::TagSizedArray(), Span(), TypeRef(Span(), ::AST::Path("test", { ::AST::PathNode("TestDescAndFn") })), ::std::shared_ptr<::AST::ExprNode>( new ::AST::ExprNode_Integer(test_count, CORETYPE_UINT) ) ), ::AST::Expr( mv$(tests_array) ) }; // ---- module ---- auto newmod = ::AST::Module { ::AST::Path("", { ::AST::PathNode("test#") }) }; // - TODO: These need to be loaded too. // > They don't actually need to exist here, just be loaded (and use absolute paths) newmod.add_ext_crate(Span(), false, "std", "std", {}); newmod.add_ext_crate(Span(), false, "test", "test", {}); newmod.add_item(Span(), false, "main", mv$(main_fn), {}); newmod.add_item(Span(), false, "TESTS", mv$(tests_list), {}); crate.m_root_module.add_item(Span(), false, "test#", mv$(newmod), {}); crate.m_lang_items["mrustc-main"] = ::AST::Path("", { AST::PathNode("test#"), AST::PathNode("main") }); }