#include #include #include "../src/StaticPass.hpp" #include "../src/Logger.hpp" #include "../src/Lexer.hpp" #include "../src/Parser.hpp" #include "src/Prototype.hpp" #include "src/SymTable.hpp" #include "src/Loader.hpp" #include "src/types.hpp" class StaticPassTest { public: explicit StaticPassTest() {} virtual ~StaticPassTest() {} void test_ok(std::string const& source, std::function init) { grino::Logger logger; grino::Lexer lexer {logger, "tests/parser"}; grino::Parser parser {logger, lexer}; grino::SymTable sym {logger}; grino::Addr addr; grino::Compiler compiler {logger, addr}; grino::StaticPass pass {logger, compiler, sym}; grino::Program prog; grino::VM vm {logger, prog}; grino::Loader loader {vm, compiler, sym}; init(loader); auto root = parser.parse(source); INFO("source: " << source); REQUIRE_NOTHROW(pass.check(root)); } void test_ko(std::string const& source, std::function init) { grino::Logger logger; grino::Lexer lexer {logger, "tests/parser"}; grino::Parser parser {logger, lexer}; grino::SymTable sym {logger}; grino::Addr addr; grino::Compiler compiler {logger, addr}; grino::StaticPass pass {logger, compiler, sym}; grino::Program prog; grino::VM vm {logger, prog}; grino::Loader loader {vm, compiler, sym}; init(loader); auto root = parser.parse(source); INFO("source: " << source); REQUIRE_THROWS_AS(pass.check(root), grino::static_error); } protected: }; TEST_CASE_METHOD(StaticPassTest, "StaticPass_normal") { grino::TypeSlot ty_int_param { grino::HintCatType::HINT_CAT_PARAM, grino::TYPE_INT }; grino::TypeSlot ty_int_ret { grino::HintCatType::HINT_CAT_RETURN, grino::TYPE_INT }; auto slots = std::vector {ty_int_param, ty_int_param, ty_int_ret}; auto proto = std::make_shared(slots); test_ok("(+ 45 1)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ko("(+ 45.2 1)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ko("(+ (+ 45.2 1) 3)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); } TEST_CASE_METHOD(StaticPassTest, "StaticPass_hint_any") { grino::TypeSlot ty_int_param { grino::HintCatType::HINT_CAT_PARAM, grino::TYPE_INT }; grino::TypeSlot ty_any_param { grino::HintCatType::HINT_CAT_PARAM, grino::TYPE_INT, grino::HINT_ANY }; grino::TypeSlot ty_int_ret { grino::HintCatType::HINT_CAT_RETURN, grino::TYPE_INT }; auto slots = std::vector {ty_int_param, ty_any_param, ty_int_ret}; auto proto = std::make_shared(slots); test_ok("(+ 45 1)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ko("(+ 45.2 1)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ 45 1.3)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ (+ 2 1) 3)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ (+ 2 1) 3.2)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ko("(+ 7.14 (+ 2 1))", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); } TEST_CASE_METHOD(StaticPassTest, "StaticPass_hint_same") { grino::TypeSlot ty_any_param { grino::HintCatType::HINT_CAT_PARAM, grino::TYPE_NIL, grino::HINT_ANY }; grino::TypeSlot ty_same_param { grino::HintCatType::HINT_CAT_PARAM, grino::TYPE_NIL, grino::HINT_SAME }; grino::TypeSlot ty_int_ret { grino::HintCatType::HINT_CAT_RETURN, grino::TYPE_INT }; auto slots = std::vector {ty_any_param, ty_same_param, ty_int_ret}; auto proto = std::make_shared(slots); test_ok("(+ 45 1)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ 45.2 1.3)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ false true)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ko("(+ false 3.2)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ko("(+ 3.7 9)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); } TEST_CASE_METHOD(StaticPassTest, "StaticPass_int_variadic") { grino::TypeSlot ty_same_param { grino::HintCatType::HINT_CAT_PARAM, grino::TYPE_NIL, grino::HINT_SAME }; grino::TypeSlot ty_var_param { grino::HintCatType::HINT_CAT_VARIADIC_PARAM, grino::TYPE_INT }; grino::TypeSlot ty_int_ret { grino::HintCatType::HINT_CAT_RETURN, grino::TYPE_INT }; auto slots = std::vector { ty_same_param, ty_var_param, ty_int_ret }; auto proto = std::make_shared(slots); test_ok("(+ 45 1 3 2 1 7)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ 45 1 7)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ko("(+ 45 3.12 1 7)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); } TEST_CASE_METHOD(StaticPassTest, "StaticPass_any_variadic") { grino::TypeSlot ty_same_param { grino::HintCatType::HINT_CAT_PARAM, grino::TYPE_NIL, grino::HINT_SAME }; grino::TypeSlot ty_var_param { grino::HintCatType::HINT_CAT_VARIADIC_PARAM, grino::TYPE_INT, grino::HINT_ANY }; grino::TypeSlot ty_int_ret { grino::HintCatType::HINT_CAT_RETURN, grino::TYPE_INT }; auto slots = std::vector { ty_same_param, ty_var_param, ty_int_ret }; auto proto = std::make_shared(slots); test_ok("(+ 45 1 3 2 1 7)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ 45 1 7)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ 45 3.12 1 7)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); test_ok("(+ 45 3.12 true 'salut' 7)", [&proto](auto& loader){ grino::Loc loc {"tests/static_pass"}; loader.add_native("+", [loader, loc](auto args){ auto lhs = args[0]; auto rhs = args[1]; return grino::Value::make_int(loc, lhs->as_int() + rhs->as_int()); }, proto); }); }