380 lines
10 KiB
C++
380 lines
10 KiB
C++
|
#include <catch2/catch.hpp>
|
||
|
#include <memory>
|
||
|
#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<void(grino::Loader&)> 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<void(grino::Loader&)> 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<grino::TypeSlot> {ty_int_param,
|
||
|
ty_int_param,
|
||
|
ty_int_ret};
|
||
|
|
||
|
auto proto = std::make_shared<grino::Prototype>(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<grino::TypeSlot> {ty_int_param,
|
||
|
ty_any_param,
|
||
|
ty_int_ret};
|
||
|
|
||
|
auto proto = std::make_shared<grino::Prototype>(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<grino::TypeSlot> {ty_any_param,
|
||
|
ty_same_param,
|
||
|
ty_int_ret};
|
||
|
|
||
|
auto proto = std::make_shared<grino::Prototype>(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<grino::TypeSlot> {
|
||
|
ty_same_param,
|
||
|
ty_var_param,
|
||
|
ty_int_ret
|
||
|
};
|
||
|
|
||
|
auto proto = std::make_shared<grino::Prototype>(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<grino::TypeSlot> {
|
||
|
ty_same_param,
|
||
|
ty_var_param,
|
||
|
ty_int_ret
|
||
|
};
|
||
|
|
||
|
auto proto = std::make_shared<grino::Prototype>(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);
|
||
|
});
|
||
|
}
|