ADD: more type checking.

main
bog 2023-09-15 11:11:06 +02:00
parent e12ff96943
commit 792ef70df9
9 changed files with 179 additions and 67 deletions

View File

@ -1,4 +1,5 @@
#include "commons.hpp"
#include "src/Prototype.hpp"
extern "C" void lib_cast(grino::Loader& loader)
{
@ -7,20 +8,32 @@ extern "C" void lib_cast(grino::Loader& loader)
loader.add_native("stoi", [loc](auto args){
std::string value = args[0]->as_string();
return grino::Value::make_int(loc, std::stoi(value));
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_STRING},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_INT}
}));
loader.add_native("itos", [loc](auto args){
int value = args[0]->as_int();
return grino::Value::make_string(loc, std::to_string(value));
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_STRING}
}));
loader.add_native("stof", [loc](auto args){
std::string value = args[0]->as_string();
return grino::Value::make_int(loc, std::stof(value));
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_STRING},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_FLOAT}
}));
loader.add_native("ftos", [loc](auto args){
float value = args[0]->as_float();
return grino::Value::make_string(loc, std::to_string(value));
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_FLOAT},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_STRING}
}));
}

View File

@ -45,8 +45,8 @@ extern "C" void lib_collection(grino::Loader& loader)
return f(args[0], idxs);
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT},
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_NIL, grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM, grino::TYPE_NIL,
grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_NIL, grino::HINT_ANY},
}));
@ -63,7 +63,11 @@ extern "C" void lib_collection(grino::Loader& loader)
auto& array = array_val->as_array();
return grino::Value::make_bool(array_val->loc(), array.empty());
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {
{grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_NIL,
grino::HINT_ANY}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_BOOL}}
}));
loader.add_native("len", [&loader](auto args){
auto val = args[0];
@ -78,7 +82,12 @@ extern "C" void lib_collection(grino::Loader& loader)
auto& array = array_val->as_array();
return grino::Value::make_int(array_val->loc(), array.size());
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {
{grino::TypeSlot {grino::HINT_CAT_PARAM,
grino::TYPE_NIL,
grino::HINT_ANY}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_INT}}
}));
}
extern "C" void lib_array(grino::Loader& loader)
@ -90,7 +99,13 @@ extern "C" void lib_array(grino::Loader& loader)
auto& array = array_val->as_array();
return array[0];
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {
{grino::TypeSlot {grino::HINT_CAT_PARAM,
grino::TYPE_ARRAY,
grino::HINT_NONE}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_NIL,
grino::HINT_ANY}}
}));
loader.add_native("tail", [&loader](auto args){
auto ref_val = args[0];
@ -109,7 +124,13 @@ extern "C" void lib_array(grino::Loader& loader)
loader.vm().set_heap(addr, res);
return grino::Value::make_ref(array_val->loc(), addr);
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {
{grino::TypeSlot {grino::HINT_CAT_PARAM,
grino::TYPE_ARRAY,
grino::HINT_NONE}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_ARRAY,
grino::HINT_NONE}}
}));
loader.add_native("cons", [&loader](auto args){
auto ref_val = args[1];
@ -124,7 +145,16 @@ extern "C" void lib_array(grino::Loader& loader)
loader.vm().set_heap(addr, res);
return grino::Value::make_ref(array_val->loc(), addr);
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {
{grino::TypeSlot {grino::HINT_CAT_PARAM,
grino::TYPE_NIL,
grino::HINT_ANY}},
{grino::TypeSlot {grino::HINT_CAT_PARAM,
grino::TYPE_ARRAY,
grino::HINT_NONE}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_ARRAY,
grino::HINT_NONE}}
}));
}
extern "C" void lib_flow_control(grino::Loader& loader)
@ -147,9 +177,13 @@ extern "C" void lib_flow_control(grino::Loader& loader)
prog.set_param(br, prog.size());
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {{
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM,
grino::TYPE_NIL,
grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_RETURN,
grino::TYPE_NIL,
grino::HINT_NONE},
grino::HINT_ANY},
}}));
}
@ -311,7 +345,7 @@ extern "C" void lib_float(grino::Loader& loader)
auto var_proto =
std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM, grino::TYPE_FLOAT},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_INT},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_FLOAT},
});
loader.add_native("+.", [](auto args){
@ -463,8 +497,10 @@ extern "C" void lib_cmp(grino::Loader& loader)
{
auto var_proto =
std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT},
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT},
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT,
grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT,
grino::HINT_SAME},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_BOOL},
});
@ -647,6 +683,8 @@ extern "C" void lib_bool(grino::Loader& loader)
extern "C" void lib_assert(grino::Loader& loader)
{
grino::Loc loc {"core/assert"};
loader.add_native("assert", [](auto args){
for (auto value: args)
@ -662,11 +700,12 @@ extern "C" void lib_assert(grino::Loader& loader)
return grino::Value::make_bool(args.front()->loc(), true);
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_BOOL},
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_NIL,
grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_NIL}
}}));
loader.add_native("assert=", [](auto args){
loader.add_native("assert=", [loc](auto args){
auto lhs = args.front();
for (size_t i=1; i<args.size(); i++)
@ -689,7 +728,13 @@ extern "C" void lib_assert(grino::Loader& loader)
}
return grino::Value::make_bool(args.front()->loc(), true);
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_NIL,
grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_NIL,
grino::HINT_SAME},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_NIL}
}}));
}
extern "C" void lib_string(grino::Loader& loader)
@ -705,18 +750,28 @@ extern "C" void lib_string(grino::Loader& loader)
}
return grino::Value::make_string(args[0]->loc(), result);
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {
{grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_STRING}},
{grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_STRING}}
}));
loader.add_native("cat", [](auto args) {
std::string result;
for (auto arg: args)
{
result += arg->as_string();
if (arg->type() == grino::TYPE_STRING)
{
result += arg->as_string();
}
}
return grino::Value::make_string(args[0]->loc(), result);
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {
{grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM, grino::TYPE_STRING}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_STRING}}
}));
}
extern "C" void lib(grino::Loader& loader)
@ -745,7 +800,13 @@ extern "C" void lib(grino::Loader& loader)
std::cout << ss.str() << std::endl;
return grino::Value::make_nil(args.back()->loc());
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
{grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM,
grino::TYPE_NIL,
grino::HINT_ANY}},
{grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_NIL}}
}));
loader.add_static("set!", [](auto& compiler,
auto node,

View File

@ -11,7 +11,11 @@ extern "C" void lib_io(grino::Loader& loader)
std::cout << arg->string();
}
return grino::Value::make_nil(grino::Loc {"io"});
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM, grino::TYPE_NIL,
grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_NIL, grino::HINT_ANY},
}));
mod->loader()->add_native("println", [](auto args){
for (auto arg: args)
@ -20,12 +24,18 @@ extern "C" void lib_io(grino::Loader& loader)
}
std::cout << std::endl;
return grino::Value::make_nil(grino::Loc {"io"});
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM, grino::TYPE_NIL,
grino::HINT_ANY},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_NIL, grino::HINT_ANY},
}));
mod->loader()->add_native("read", [](auto args){
std::string value;
std::cin >> value;
return grino::Value::make_string(grino::Loc {"io"}, value);
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_STRING},
}));
}

View File

@ -17,7 +17,9 @@ extern "C" void lib_rand(grino::Loader& loader)
std::uniform_real_distribution<float> urd(0.0f, 1.0f);
return grino::Value::make_float(loc, urd(r));
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_FLOAT},
}));
mod->loader()->add_native("range", [loc](auto args){
std::mt19937 r;
@ -29,5 +31,9 @@ extern "C" void lib_rand(grino::Loader& loader)
std::uniform_int_distribution<int> dist(from, to);
return grino::Value::make_int(loc, dist(r));
});
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT},
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_INT},
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_INT},
}));
}

View File

@ -51,6 +51,14 @@ namespace grino
else
{
auto entry = sym.find_no_scope(name);
if (!entry)
{
std::stringstream ss;
ss << "cannot import unknown module '" << name << "'";
m_logger.log<compile_error>(LOG_ERROR, node->loc(), ss.str());
}
assert(entry);
assert(entry->is_object);

View File

@ -93,15 +93,6 @@ namespace grino
return mod;
}
void Loader::add_native(std::string const& name, native_t native)
{
size_t addr = m_vm.heap_size();
grino::Loc loc {"natives/" + name, 0};
m_vm.set_heap(addr, grino::Value::make_native_function(loc, native));
m_sym_table.declare_object(loc, name, addr, 0);
}
void Loader::add_native(std::string const& name,
native_t native,
std::shared_ptr<Prototype> prototype)

View File

@ -26,8 +26,6 @@ namespace grino
void load_library(std::filesystem::path path);
std::shared_ptr<Module> add_module(std::string const& name);
void add_native(std::string const& name, native_t native);
void add_native(std::string const& name,
native_t native,
std::shared_ptr<Prototype> prototype);

View File

@ -1,6 +1,7 @@
#include "StaticPass.hpp"
#include "src/Prototype.hpp"
#include "StaticFunction.hpp"
#include "src/types.hpp"
namespace grino
{
@ -17,18 +18,19 @@ namespace grino
{
}
TypeType StaticPass::check(std::shared_ptr<Node> node)
TypeSlot StaticPass::check(std::shared_ptr<Node> node)
{
switch (node->type())
{
case NODE_ARRAY:
case NODE_BLOCK: {
TypeSlot res;
for (size_t i=0; i<node->size(); i++)
{
check(node->child(i).lock());
res = check(node->child(i).lock());
}
return TYPE_NIL;
return res;
} break;
case NODE_MODULE: {
@ -37,23 +39,31 @@ namespace grino
check(node->child(i).lock());
}
return TYPE_MODULE;
return TypeSlot{HINT_CAT_RETURN, TYPE_MODULE};
} break;
case NODE_NS: {
return TypeSlot{HINT_CAT_RETURN, TYPE_NIL, HINT_ANY};
} break;
case NODE_ARRAY: {
return TypeSlot{HINT_CAT_RETURN, TYPE_ARRAY};
} break;
case NODE_INT: {
return TYPE_INT;
return TypeSlot{HINT_CAT_RETURN, TYPE_INT};
} break;
case NODE_FLOAT: {
return TYPE_FLOAT;
return TypeSlot{HINT_CAT_RETURN, TYPE_FLOAT};
} break;
case NODE_BOOL: {
return TYPE_BOOL;
return TypeSlot{HINT_CAT_RETURN, TYPE_BOOL};
} break;
case NODE_STRING: {
return TYPE_STRING;
return TypeSlot{HINT_CAT_RETURN, TYPE_STRING};
} break;
case NODE_IDENT: {
@ -62,11 +72,11 @@ namespace grino
} break;
case NODE_LAMBDA: {
return TYPE_FUNCTION;
return TypeSlot{HINT_CAT_RETURN, TYPE_FUNCTION};
} break;
case NODE_IMPORT: {
return TYPE_MODULE;
return TypeSlot{HINT_CAT_RETURN, TYPE_MODULE};
} break;
case NODE_VARDECL: {
@ -105,14 +115,20 @@ namespace grino
{
auto param_ty = check(node->child(i).lock());
if (param_ty != ty
if (param_ty.hint == HINT_ANY)
{
continue;
}
if (param_ty.type != ty
&& param_ty.hint != HINT_ANY
&& var_params.back().hint != HINT_ANY)
{
error(ty, param_ty, node->loc());
error(ty, param_ty.type, node);
}
}
return rets[0].type;
return TypeSlot {HINT_CAT_RETURN, rets[0].type, rets[0].hint};
}
if (params.size() != node->size() - 1)
@ -128,35 +144,41 @@ namespace grino
.log<static_error>(LOG_ERROR, node->loc(), ss.str());
}
std::vector<TypeType> ty;
std::vector<TypeSlot> ty;
for (size_t i=1; i<node->size(); i++)
{
TypeType param_ty = check(node->child(i).lock());
auto param_ty = check(node->child(i).lock());
ty.push_back(param_ty);
if (proto->hint(i - 1) == HINT_ANY)
if (proto->hint(i - 1) == HINT_ANY
|| param_ty.hint == HINT_ANY)
{
continue;
}
bool same_err = (i > 1 && proto->hint(i - 1) == HINT_SAME)
&& ty.back() != ty.at(ty.size() - 2);
&& ty.back().type != ty.at(ty.size() - 2).type;
if (same_err)
{
error(ty.at(ty.size() - 2).type, ty.back().type, node);
}
bool normal_err = proto->hint(i - 1) == HINT_NONE
&& param_ty != proto->type(i - 1);
&& param_ty.type != proto->type(i - 1);
if (same_err || normal_err)
if (normal_err)
{
error(proto->type(i - 1), param_ty, node->loc());
error(proto->type(i - 1), param_ty.type, node);
}
}
assert(rets.size() > 0);
return rets[0].type;
return TypeSlot { HINT_CAT_RETURN, rets[0].type, rets[0].hint};
}
return TYPE_NIL;
return TypeSlot{HINT_CAT_RETURN, TYPE_NIL, HINT_ANY};
} break;
default:
@ -168,16 +190,19 @@ namespace grino
abort();
}
void StaticPass::error(TypeType lhs, TypeType rhs, Loc const& loc)
void StaticPass::error(TypeType lhs, TypeType rhs,
std::shared_ptr<Node> node)
{
std::stringstream ss;
ss << "type mismatch, expected '"
ss << "type mismatch in '"
<< GRINO_TRIM(NodeTypeStr[node->type()], "NODE_")
<< "', expected '"
<< GRINO_TRIM(TypeTypeStr[lhs], "TYPE_")
<< "', got '"
<< GRINO_TRIM(TypeTypeStr[rhs], "TYPE_")
<< "'";
m_logger
.log<static_error>(LOG_ERROR, loc, ss.str());
.log<static_error>(LOG_ERROR, node->loc(), ss.str());
}
}

View File

@ -17,15 +17,15 @@ namespace grino
explicit StaticPass(Logger& logger, Compiler& compiler, SymTable& sym);
virtual ~StaticPass();
TypeType check(std::shared_ptr<Node> node);
TypeSlot check(std::shared_ptr<Node> node);
private:
Logger& m_logger;
Compiler& m_compiler;
SymTable& m_sym;
std::unordered_map<std::string, TypeType> m_types;
std::unordered_map<std::string, TypeSlot> m_types;
void error(TypeType lhs, TypeType rhs, Loc const& loc);
void error(TypeType lhs, TypeType rhs, std::shared_ptr<Node> node);
};
}