From 792ef70df9ca84366634006b65c269125359dbef Mon Sep 17 00:00:00 2001 From: bog Date: Fri, 15 Sep 2023 11:11:06 +0200 Subject: [PATCH] ADD: more type checking. --- lib/cast.hpp | 21 ++++++++-- lib/core.cpp | 97 +++++++++++++++++++++++++++++++++++++--------- lib/std/io.hpp | 16 ++++++-- lib/std/rand.hpp | 10 ++++- src/Compiler.cpp | 8 ++++ src/Loader.cpp | 9 ----- src/Loader.hpp | 2 - src/StaticPass.cpp | 77 +++++++++++++++++++++++------------- src/StaticPass.hpp | 6 +-- 9 files changed, 179 insertions(+), 67 deletions(-) diff --git a/lib/cast.hpp b/lib/cast.hpp index d0d8d4f..f0f6f44 100644 --- a/lib/cast.hpp +++ b/lib/cast.hpp @@ -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(std::vector{ + 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(std::vector{ + 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(std::vector{ + 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(std::vector{ + grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_FLOAT}, + grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_STRING} + })); } diff --git a/lib/core.cpp b/lib/core.cpp index dbc62e4..b592025 100644 --- a/lib/core.cpp +++ b/lib/core.cpp @@ -45,8 +45,8 @@ extern "C" void lib_collection(grino::Loader& loader) return f(args[0], idxs); }, std::make_shared(std::vector{ - 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(std::vector { + {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(std::vector { + {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(std::vector { + {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(std::vector { + {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(std::vector { + {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(std::vector {{ + 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(std::vector{ 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(std::vector{ - 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(std::vector {{ - 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; iloc(), true); - }); + }, std::make_shared(std::vector {{ + 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(std::vector { + {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(std::vector { + {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(std::vector{ + {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, diff --git a/lib/std/io.hpp b/lib/std/io.hpp index b5a6076..57d4bbe 100644 --- a/lib/std/io.hpp +++ b/lib/std/io.hpp @@ -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(std::vector{ + 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(std::vector{ + 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(std::vector{ + grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_STRING}, + })); } diff --git a/lib/std/rand.hpp b/lib/std/rand.hpp index 7cfb7ac..31a9626 100644 --- a/lib/std/rand.hpp +++ b/lib/std/rand.hpp @@ -17,7 +17,9 @@ extern "C" void lib_rand(grino::Loader& loader) std::uniform_real_distribution urd(0.0f, 1.0f); return grino::Value::make_float(loc, urd(r)); - }); + }, std::make_shared(std::vector{ + 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 dist(from, to); return grino::Value::make_int(loc, dist(r)); - }); + }, std::make_shared(std::vector{ + 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}, + })); } diff --git a/src/Compiler.cpp b/src/Compiler.cpp index 1cf906d..854039f 100644 --- a/src/Compiler.cpp +++ b/src/Compiler.cpp @@ -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(LOG_ERROR, node->loc(), ss.str()); + } + assert(entry); assert(entry->is_object); diff --git a/src/Loader.cpp b/src/Loader.cpp index 3372952..b34d80f 100644 --- a/src/Loader.cpp +++ b/src/Loader.cpp @@ -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) diff --git a/src/Loader.hpp b/src/Loader.hpp index 8bea6e8..d5793e1 100644 --- a/src/Loader.hpp +++ b/src/Loader.hpp @@ -26,8 +26,6 @@ namespace grino void load_library(std::filesystem::path path); std::shared_ptr 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); diff --git a/src/StaticPass.cpp b/src/StaticPass.cpp index 385922d..f0142b9 100644 --- a/src/StaticPass.cpp +++ b/src/StaticPass.cpp @@ -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) + TypeSlot StaticPass::check(std::shared_ptr node) { switch (node->type()) { - case NODE_ARRAY: case NODE_BLOCK: { + TypeSlot res; + for (size_t i=0; isize(); 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(LOG_ERROR, node->loc(), ss.str()); } - std::vector ty; + std::vector ty; for (size_t i=1; isize(); 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) { 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(LOG_ERROR, loc, ss.str()); + .log(LOG_ERROR, node->loc(), ss.str()); } } diff --git a/src/StaticPass.hpp b/src/StaticPass.hpp index 7c40be8..e98a760 100644 --- a/src/StaticPass.hpp +++ b/src/StaticPass.hpp @@ -17,15 +17,15 @@ namespace grino explicit StaticPass(Logger& logger, Compiler& compiler, SymTable& sym); virtual ~StaticPass(); - TypeType check(std::shared_ptr node); + TypeSlot check(std::shared_ptr node); private: Logger& m_logger; Compiler& m_compiler; SymTable& m_sym; - std::unordered_map m_types; + std::unordered_map m_types; - void error(TypeType lhs, TypeType rhs, Loc const& loc); + void error(TypeType lhs, TypeType rhs, std::shared_ptr node); }; }