ADD: basic type checker.
parent
29facf1647
commit
e12ff96943
|
@ -1,5 +1,5 @@
|
|||
#include "../src/Loader.hpp"
|
||||
#include "src/Logger.hpp"
|
||||
#include "src/Value.hpp"
|
||||
#include "src/opcodes.hpp"
|
||||
#include "../src/Logger.hpp"
|
||||
#include "../src/Value.hpp"
|
||||
#include "../src/opcodes.hpp"
|
||||
#include "../src/Module.hpp"
|
||||
|
|
127
lib/core.cpp
127
lib/core.cpp
|
@ -1,9 +1,11 @@
|
|||
#include "../src/Loader.hpp"
|
||||
#include "src/Logger.hpp"
|
||||
#include "src/Prototype.hpp"
|
||||
#include "src/Value.hpp"
|
||||
#include "src/opcodes.hpp"
|
||||
#include "../src/Module.hpp"
|
||||
#include "cast.hpp"
|
||||
#include "src/types.hpp"
|
||||
|
||||
GRINO_ERROR(assertion_error);
|
||||
|
||||
|
@ -42,7 +44,11 @@ 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_RETURN, grino::TYPE_NIL, grino::HINT_ANY},
|
||||
}));
|
||||
|
||||
loader.add_native("empty?", [&loader](auto args){
|
||||
auto val = args[0];
|
||||
|
@ -140,11 +146,21 @@ extern "C" void lib_flow_control(grino::Loader& loader)
|
|||
compiler.compile(else_node, prog, sym);
|
||||
|
||||
prog.set_param(br, prog.size());
|
||||
});
|
||||
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {{
|
||||
grino::TypeSlot {grino::HINT_CAT_RETURN,
|
||||
grino::TYPE_NIL,
|
||||
grino::HINT_NONE},
|
||||
}}));
|
||||
}
|
||||
|
||||
extern "C" void lib_int(grino::Loader& loader)
|
||||
{
|
||||
auto var_proto =
|
||||
std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot>{
|
||||
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM, grino::TYPE_INT},
|
||||
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_INT},
|
||||
});
|
||||
|
||||
loader.add_native("+", [](auto args){
|
||||
int result = 0;
|
||||
|
||||
|
@ -161,7 +177,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_int(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("*", [](auto args){
|
||||
int result = 1;
|
||||
|
@ -179,7 +195,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_int(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("-", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -206,7 +222,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_int(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("/", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -233,7 +249,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_int(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("%", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -260,7 +276,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_int(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("^", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -287,11 +303,17 @@ extern "C" void lib_int(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_int(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
}
|
||||
|
||||
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},
|
||||
});
|
||||
|
||||
loader.add_native("+.", [](auto args){
|
||||
float result = 0;
|
||||
|
||||
|
@ -308,7 +330,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("*.", [](auto args){
|
||||
float result = 1;
|
||||
|
@ -326,7 +348,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("-.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -353,7 +375,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("/.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -380,7 +402,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("%.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -407,7 +429,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("^.", [](auto args){
|
||||
grino::Loc loc {"???", 0};
|
||||
|
@ -434,11 +456,18 @@ extern "C" void lib_float(grino::Loader& loader)
|
|||
}
|
||||
|
||||
return grino::Value::make_float(loc, result);
|
||||
});
|
||||
}, var_proto);
|
||||
}
|
||||
|
||||
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_RETURN, grino::TYPE_BOOL},
|
||||
});
|
||||
|
||||
loader.add_native("<", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
{
|
||||
|
@ -456,7 +485,7 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
|||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("<=", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
|
@ -475,7 +504,7 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
|||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native(">", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
|
@ -494,7 +523,7 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
|||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native(">=", [](auto args){
|
||||
if (args[0]->type() == grino::TYPE_INT)
|
||||
|
@ -513,21 +542,33 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
|||
}
|
||||
|
||||
assert(0);
|
||||
});
|
||||
}, var_proto);
|
||||
|
||||
loader.add_native("ne?", [](auto args){
|
||||
auto lhs = args[0];
|
||||
auto rhs = args[1];
|
||||
|
||||
return grino::Value::make_bool(args[0]->loc(), !lhs->equals(*rhs));
|
||||
});
|
||||
}, 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_BOOL}
|
||||
}}));
|
||||
}
|
||||
|
||||
extern "C" void lib_bool(grino::Loader& loader)
|
||||
{
|
||||
loader.add_native("not", [](auto args){
|
||||
return grino::Value::make_bool(args[0]->loc(), !args[0]->as_bool());
|
||||
});
|
||||
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {{
|
||||
grino::TypeSlot {grino::HINT_CAT_PARAM, grino::TYPE_BOOL},
|
||||
grino::TypeSlot {grino::HINT_CAT_RETURN, grino::TYPE_BOOL}
|
||||
}}));
|
||||
|
||||
loader.add_static("and", [](auto& compiler, auto node,
|
||||
auto& program,
|
||||
|
@ -557,7 +598,14 @@ extern "C" void lib_bool(grino::Loader& loader)
|
|||
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
||||
|
||||
program.set_param(to_end, program.size());
|
||||
});
|
||||
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {{
|
||||
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM,
|
||||
grino::TYPE_BOOL,
|
||||
grino::HINT_NONE},
|
||||
grino::TypeSlot {grino::HINT_CAT_RETURN,
|
||||
grino::TYPE_BOOL,
|
||||
grino::HINT_NONE},
|
||||
}}));
|
||||
|
||||
loader.add_static("or", [](auto& compiler, auto node,
|
||||
auto& program, auto& sym){
|
||||
|
@ -587,7 +635,14 @@ extern "C" void lib_bool(grino::Loader& loader)
|
|||
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
||||
|
||||
program.set_param(to_end, program.size());
|
||||
});
|
||||
}, std::make_shared<grino::Prototype>(std::vector<grino::TypeSlot> {{
|
||||
grino::TypeSlot {grino::HINT_CAT_VARIADIC_PARAM,
|
||||
grino::TYPE_BOOL,
|
||||
grino::HINT_NONE},
|
||||
grino::TypeSlot {grino::HINT_CAT_RETURN,
|
||||
grino::TYPE_BOOL,
|
||||
grino::HINT_NONE},
|
||||
}}));
|
||||
}
|
||||
|
||||
extern "C" void lib_assert(grino::Loader& loader)
|
||||
|
@ -606,7 +661,10 @@ 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_RETURN, grino::TYPE_NIL}
|
||||
}}));
|
||||
|
||||
loader.add_native("assert=", [](auto args){
|
||||
auto lhs = args.front();
|
||||
|
@ -705,7 +763,17 @@ extern "C" void lib(grino::Loader& loader)
|
|||
}
|
||||
|
||||
program.push_value(grino::Value::make_nil(node->loc()));
|
||||
});
|
||||
}, 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,
|
||||
grino::HINT_NONE}
|
||||
}}));
|
||||
|
||||
loader.add_native("eq?", [](auto args){
|
||||
auto lhs = args.front();
|
||||
|
@ -721,5 +789,14 @@ extern "C" void lib(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_BOOL}
|
||||
}}));
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ grino_src = shared_library('grino',
|
|||
'src/Loader.cpp',
|
||||
'src/Addr.cpp',
|
||||
'src/Module.cpp',
|
||||
'src/StaticPass.cpp',
|
||||
'src/Prototype.cpp',
|
||||
],
|
||||
install: true)
|
||||
pkg = import('pkgconfig')
|
||||
|
@ -62,6 +64,8 @@ install_headers(
|
|||
'src/Loader.hpp',
|
||||
'src/Addr.hpp',
|
||||
'src/Module.hpp',
|
||||
'src/StaticPass.hpp',
|
||||
'src/Prototype.hpp',
|
||||
], subdir: 'grino'
|
||||
)
|
||||
|
||||
|
@ -101,6 +105,7 @@ executable('grino-tests',
|
|||
'tests/main.cpp',
|
||||
'tests/Lexer.cpp',
|
||||
'tests/Parser.cpp',
|
||||
'tests/StaticPass.cpp',
|
||||
],
|
||||
dependencies: [
|
||||
grino_dep,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "Program.hpp"
|
||||
#include "Module.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "src/opcodes.hpp"
|
||||
#include "opcodes.hpp"
|
||||
#include "StaticFunction.hpp"
|
||||
|
||||
namespace grino
|
||||
|
@ -246,6 +246,11 @@ namespace grino
|
|||
}
|
||||
}
|
||||
|
||||
bool Compiler::has_static_func(std::string name) const
|
||||
{
|
||||
return m_statics.find(name) != std::end(m_statics);
|
||||
}
|
||||
|
||||
void Compiler::add_static_func(std::string const& name,
|
||||
std::shared_ptr<StaticFunction> fun)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "commons.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "src/mutils.hpp"
|
||||
#include "mutils.hpp"
|
||||
#include "Addr.hpp"
|
||||
|
||||
namespace grino
|
||||
|
@ -27,6 +27,14 @@ namespace grino
|
|||
Program& program,
|
||||
SymTable& sym);
|
||||
|
||||
std::shared_ptr<StaticFunction>
|
||||
static_func(std::string name) const {
|
||||
return m_statics.at(name);
|
||||
}
|
||||
|
||||
|
||||
bool has_static_func(std::string name) const;
|
||||
|
||||
void add_static_func(std::string const& name,
|
||||
std::shared_ptr<StaticFunction> fun);
|
||||
|
||||
|
|
|
@ -51,4 +51,8 @@ namespace grino
|
|||
m_env[addr] = value;
|
||||
}
|
||||
|
||||
void Function::set_prototype(std::shared_ptr<Prototype> prototype)
|
||||
{
|
||||
m_prototype = prototype;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define grino_FUNCTION_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "Prototype.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
@ -19,6 +20,7 @@ namespace grino
|
|||
explicit Function(std::shared_ptr<Program> prog, size_t base_addr);
|
||||
virtual ~Function();
|
||||
|
||||
std::shared_ptr<Prototype> prototype() const { return m_prototype; }
|
||||
size_t base_addr() const { return m_base_addr; }
|
||||
|
||||
bool is_native() const;
|
||||
|
@ -29,11 +31,14 @@ namespace grino
|
|||
std::shared_ptr<Value> env(size_t addr) const;
|
||||
void set_env(size_t addr, std::shared_ptr<Value> value);
|
||||
|
||||
void set_prototype(std::shared_ptr<Prototype> prototype);
|
||||
|
||||
private:
|
||||
native_t m_native;
|
||||
std::shared_ptr<Program> m_prog;
|
||||
std::unordered_map<size_t, std::shared_ptr<Value>> m_env;
|
||||
size_t m_base_addr = 0;
|
||||
std::shared_ptr<Prototype> m_prototype;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "Lexer.hpp"
|
||||
#include "src/Node.hpp"
|
||||
#include "Node.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "Loader.hpp"
|
||||
#include "Function.hpp"
|
||||
#include "src/config.in.hpp"
|
||||
#include <dlfcn.h>
|
||||
#include "Lexer.hpp"
|
||||
#include "Parser.hpp"
|
||||
|
@ -44,6 +43,11 @@ namespace grino
|
|||
return deps;
|
||||
}
|
||||
|
||||
void Loader::add_lib(std::filesystem::path path)
|
||||
{
|
||||
m_libs.push_back(path);
|
||||
}
|
||||
|
||||
void Loader::load_libraries()
|
||||
{
|
||||
for (auto entry: std::filesystem::directory_iterator(GRINO_LIBDIR))
|
||||
|
@ -54,6 +58,15 @@ namespace grino
|
|||
load_library(entry.path());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto path: m_libs)
|
||||
{
|
||||
if (path.has_extension()
|
||||
&& path.extension() == ".so")
|
||||
{
|
||||
load_library(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Loader::load_library(std::filesystem::path path)
|
||||
|
@ -61,6 +74,7 @@ namespace grino
|
|||
void* handle = dlopen(path.string().c_str(), RTLD_NOW);
|
||||
typedef void(*libfun)(Loader&);
|
||||
libfun f = (libfun) dlsym(handle, "lib");
|
||||
assert(f);
|
||||
|
||||
f(*this);
|
||||
}
|
||||
|
@ -88,8 +102,23 @@ namespace grino
|
|||
m_sym_table.declare_object(loc, name, addr, 0);
|
||||
}
|
||||
|
||||
void Loader::add_static(std::string const& name, static_fun_t fun)
|
||||
void Loader::add_native(std::string const& name,
|
||||
native_t native,
|
||||
std::shared_ptr<Prototype> prototype)
|
||||
{
|
||||
m_compiler.add_static_func(name, std::make_shared<StaticFunction>(fun));
|
||||
size_t addr = m_vm.heap_size();
|
||||
grino::Loc loc {"natives/" + name, 0};
|
||||
auto val = grino::Value::make_native_function(loc, native);
|
||||
val->as_function()->set_prototype(prototype);
|
||||
m_vm.set_heap(addr, val);
|
||||
m_sym_table.declare_function(loc, name, addr, 0, prototype);
|
||||
}
|
||||
|
||||
void Loader::add_static(std::string const& name,
|
||||
static_fun_t fun,
|
||||
std::shared_ptr<Prototype> prototype)
|
||||
{
|
||||
auto fn = std::make_shared<StaticFunction>(fun, prototype);
|
||||
m_compiler.add_static_func(name, fn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,17 +20,27 @@ namespace grino
|
|||
std::vector<std::filesystem::path>
|
||||
dependencies(std::shared_ptr<Node> node);
|
||||
|
||||
void add_lib(std::filesystem::path path);
|
||||
|
||||
void load_libraries();
|
||||
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_static(std::string const& name, static_fun_t fun);
|
||||
|
||||
void add_native(std::string const& name,
|
||||
native_t native,
|
||||
std::shared_ptr<Prototype> prototype);
|
||||
|
||||
void add_static(std::string const& name,
|
||||
static_fun_t fun,
|
||||
std::shared_ptr<Prototype> prototype);
|
||||
|
||||
private:
|
||||
VM& m_vm;
|
||||
Compiler& m_compiler;
|
||||
SymTable& m_sym_table;
|
||||
std::vector<std::filesystem::path> m_libs;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define grino_LOGGER_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "src/mutils.hpp"
|
||||
#include "mutils.hpp"
|
||||
#include "Loc.hpp"
|
||||
|
||||
#define LOG_TYPE(G) \
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "Lexer.hpp"
|
||||
#include "Parser.hpp"
|
||||
#include "Compiler.hpp"
|
||||
#include "StaticPass.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
@ -44,6 +45,9 @@ namespace grino
|
|||
m_loader = std::make_shared<Loader>(*m_vm, *m_compiler, *m_sym_table);
|
||||
m_loader->load_libraries();
|
||||
|
||||
StaticPass static_pass {m_logger, *m_compiler, *m_sym_table};
|
||||
static_pass.check(ast);
|
||||
|
||||
m_compiler->compile(ast, *m_program, *m_sym_table);
|
||||
|
||||
m_vm->run();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "Parser.hpp"
|
||||
#include "src/Node.hpp"
|
||||
#include "src/mutils.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "mutils.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "commons.hpp"
|
||||
#include "Lexer.hpp"
|
||||
#include "src/mutils.hpp"
|
||||
#include "mutils.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "Program.hpp"
|
||||
#include "src/opcodes.hpp"
|
||||
#include "opcodes.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#include "Prototype.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
/*explicit*/ Prototype::Prototype(std::vector<TypeSlot> const& types)
|
||||
: m_types { types }
|
||||
{
|
||||
}
|
||||
|
||||
/*explicit*/ Prototype::Prototype(std::vector<TypeType> const& params,
|
||||
TypeType ret)
|
||||
{
|
||||
for (auto ty: params)
|
||||
{
|
||||
m_types.push_back(TypeSlot {
|
||||
HINT_CAT_PARAM,
|
||||
ty,
|
||||
HINT_NONE
|
||||
});
|
||||
}
|
||||
|
||||
m_types.push_back(TypeSlot {
|
||||
HINT_CAT_RETURN,
|
||||
ret,
|
||||
HINT_NONE
|
||||
});
|
||||
}
|
||||
|
||||
/*virtual*/ Prototype::~Prototype()
|
||||
{
|
||||
}
|
||||
|
||||
TypeType Prototype::type(size_t index) const
|
||||
{
|
||||
assert(index < size());
|
||||
return m_types[index].type;
|
||||
}
|
||||
|
||||
HintType Prototype::hint(size_t index) const
|
||||
{
|
||||
assert(index < size());
|
||||
return m_types[index].hint;
|
||||
}
|
||||
|
||||
HintCatType Prototype::category(size_t index) const
|
||||
{
|
||||
assert(index < size());
|
||||
return m_types[index].category;
|
||||
}
|
||||
|
||||
std::vector<TypeSlot> Prototype::filter(HintCatType category) const
|
||||
{
|
||||
std::vector<TypeSlot> result;
|
||||
|
||||
for (size_t i=0; i<size(); i++)
|
||||
{
|
||||
if (m_types[i].category == category)
|
||||
{
|
||||
result.push_back(m_types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef grino_PROTOTYPE_HPP
|
||||
#define grino_PROTOTYPE_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#define HINTS(G) \
|
||||
G(HINT_NONE), \
|
||||
G(HINT_ANY), \
|
||||
G(HINT_SAME),
|
||||
|
||||
#define HINTS_CATEGORY(G) \
|
||||
G(HINT_CAT_PARAM), \
|
||||
G(HINT_CAT_VARIADIC_PARAM), \
|
||||
G(HINT_CAT_RETURN)
|
||||
|
||||
namespace grino
|
||||
{
|
||||
GRINO_ENUM(Hint, HINTS);
|
||||
GRINO_ENUM(HintCat, HINTS_CATEGORY);
|
||||
|
||||
struct TypeSlot {
|
||||
HintCatType category;
|
||||
TypeType type;
|
||||
HintType hint = HINT_NONE;
|
||||
};
|
||||
|
||||
class Prototype
|
||||
{
|
||||
public:
|
||||
explicit Prototype(std::vector<TypeSlot> const& types);
|
||||
explicit Prototype(std::vector<TypeType> const& params, TypeType ret);
|
||||
virtual ~Prototype();
|
||||
|
||||
size_t size() const { return m_types.size(); }
|
||||
|
||||
TypeType type(size_t index) const;
|
||||
HintType hint(size_t index) const;
|
||||
HintCatType category(size_t index) const;
|
||||
|
||||
std::vector<TypeSlot> filter(HintCatType category) const;
|
||||
|
||||
private:
|
||||
std::vector<TypeSlot> m_types;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
namespace grino
|
||||
{
|
||||
/*explicit*/ StaticFunction::StaticFunction(static_fun_t fun)
|
||||
/*explicit*/ StaticFunction::StaticFunction(static_fun_t fun,
|
||||
std::shared_ptr<Prototype> proto)
|
||||
: m_fun { fun }
|
||||
, m_prototype { proto }
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Node.hpp"
|
||||
#include "Program.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "Prototype.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
@ -18,13 +19,16 @@ namespace grino
|
|||
class StaticFunction
|
||||
{
|
||||
public:
|
||||
explicit StaticFunction(static_fun_t fun);
|
||||
explicit StaticFunction(static_fun_t fun, std::shared_ptr<Prototype> proto);
|
||||
virtual ~StaticFunction();
|
||||
|
||||
std::shared_ptr<Prototype> prototype() const { return m_prototype; }
|
||||
|
||||
void call(Compiler& compiler, node_t node, prog_t prog, sym_t sym);
|
||||
|
||||
private:
|
||||
static_fun_t m_fun;
|
||||
std::shared_ptr<Prototype> m_prototype;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
#include "StaticPass.hpp"
|
||||
#include "src/Prototype.hpp"
|
||||
#include "StaticFunction.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
/*explicit*/ StaticPass::StaticPass(Logger& logger,
|
||||
Compiler& compiler,
|
||||
SymTable& sym)
|
||||
: m_logger { logger }
|
||||
, m_compiler { compiler }
|
||||
, m_sym { sym }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ StaticPass::~StaticPass()
|
||||
{
|
||||
}
|
||||
|
||||
TypeType StaticPass::check(std::shared_ptr<Node> node)
|
||||
{
|
||||
switch (node->type())
|
||||
{
|
||||
case NODE_ARRAY:
|
||||
case NODE_BLOCK: {
|
||||
for (size_t i=0; i<node->size(); i++)
|
||||
{
|
||||
check(node->child(i).lock());
|
||||
}
|
||||
|
||||
return TYPE_NIL;
|
||||
} break;
|
||||
|
||||
case NODE_MODULE: {
|
||||
for (size_t i=0; i<node->size(); i++)
|
||||
{
|
||||
check(node->child(i).lock());
|
||||
}
|
||||
|
||||
return TYPE_MODULE;
|
||||
} break;
|
||||
|
||||
case NODE_INT: {
|
||||
return TYPE_INT;
|
||||
} break;
|
||||
|
||||
case NODE_FLOAT: {
|
||||
return TYPE_FLOAT;
|
||||
} break;
|
||||
|
||||
case NODE_BOOL: {
|
||||
return TYPE_BOOL;
|
||||
} break;
|
||||
|
||||
case NODE_STRING: {
|
||||
return TYPE_STRING;
|
||||
} break;
|
||||
|
||||
case NODE_IDENT: {
|
||||
std::string ident = node->repr();
|
||||
return m_types[ident];
|
||||
} break;
|
||||
|
||||
case NODE_LAMBDA: {
|
||||
return TYPE_FUNCTION;
|
||||
} break;
|
||||
|
||||
case NODE_IMPORT: {
|
||||
return TYPE_MODULE;
|
||||
} break;
|
||||
|
||||
case NODE_VARDECL: {
|
||||
std::string ident = node->child(0).lock()->repr();
|
||||
auto res = check(node->child(1).lock());
|
||||
m_types[ident] = res;
|
||||
return res;
|
||||
} break;
|
||||
|
||||
case NODE_FUNCALL: {
|
||||
std::string ident = node->child(0).lock()->repr();
|
||||
std::shared_ptr<Prototype> proto;
|
||||
auto entry = m_sym.find_no_scope(ident);
|
||||
|
||||
if (entry && entry->prototype)
|
||||
{
|
||||
proto = entry->prototype;
|
||||
}
|
||||
else if (m_compiler.has_static_func(ident))
|
||||
{
|
||||
proto = m_compiler.static_func(ident)->prototype();
|
||||
}
|
||||
|
||||
if (proto)
|
||||
{
|
||||
auto params = proto->filter(HINT_CAT_PARAM);
|
||||
auto rets = proto->filter(HINT_CAT_RETURN);
|
||||
|
||||
auto var_params = proto->filter(HINT_CAT_VARIADIC_PARAM);
|
||||
|
||||
if (!var_params.empty())
|
||||
{
|
||||
TypeType ty = var_params.back().type;
|
||||
|
||||
for (size_t i=1; i<node->size(); i++)
|
||||
{
|
||||
auto param_ty = check(node->child(i).lock());
|
||||
|
||||
if (param_ty != ty
|
||||
&& var_params.back().hint != HINT_ANY)
|
||||
{
|
||||
error(ty, param_ty, node->loc());
|
||||
}
|
||||
}
|
||||
|
||||
return rets[0].type;
|
||||
}
|
||||
|
||||
if (params.size() != node->size() - 1)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "arity mismatch, expected '"
|
||||
<< params.size()
|
||||
<< "' got '"
|
||||
<< (node->size() - 1)
|
||||
<< "'";
|
||||
std::cout << node->string() << std::endl;
|
||||
m_logger
|
||||
.log<static_error>(LOG_ERROR, node->loc(), ss.str());
|
||||
}
|
||||
|
||||
std::vector<TypeType> ty;
|
||||
|
||||
for (size_t i=1; i<node->size(); i++)
|
||||
{
|
||||
TypeType param_ty = check(node->child(i).lock());
|
||||
ty.push_back(param_ty);
|
||||
|
||||
if (proto->hint(i - 1) == HINT_ANY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool same_err = (i > 1 && proto->hint(i - 1) == HINT_SAME)
|
||||
&& ty.back() != ty.at(ty.size() - 2);
|
||||
|
||||
bool normal_err = proto->hint(i - 1) == HINT_NONE
|
||||
&& param_ty != proto->type(i - 1);
|
||||
|
||||
if (same_err || normal_err)
|
||||
{
|
||||
error(proto->type(i - 1), param_ty, node->loc());
|
||||
}
|
||||
}
|
||||
|
||||
assert(rets.size() > 0);
|
||||
return rets[0].type;
|
||||
}
|
||||
|
||||
return TYPE_NIL;
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
std::cerr << "cannot check node "
|
||||
<< NodeTypeStr[node->type()] << std::endl;
|
||||
abort();
|
||||
}
|
||||
|
||||
void StaticPass::error(TypeType lhs, TypeType rhs, Loc const& loc)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "type mismatch, expected '"
|
||||
<< GRINO_TRIM(TypeTypeStr[lhs], "TYPE_")
|
||||
<< "', got '"
|
||||
<< GRINO_TRIM(TypeTypeStr[rhs], "TYPE_")
|
||||
<< "'";
|
||||
|
||||
m_logger
|
||||
.log<static_error>(LOG_ERROR, loc, ss.str());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef grino_STATICPASS_HPP
|
||||
#define grino_STATICPASS_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "Compiler.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
GRINO_ERROR(static_error);
|
||||
|
||||
class StaticPass
|
||||
{
|
||||
public:
|
||||
explicit StaticPass(Logger& logger, Compiler& compiler, SymTable& sym);
|
||||
virtual ~StaticPass();
|
||||
|
||||
TypeType check(std::shared_ptr<Node> node);
|
||||
|
||||
private:
|
||||
Logger& m_logger;
|
||||
Compiler& m_compiler;
|
||||
SymTable& m_sym;
|
||||
std::unordered_map<std::string, TypeType> m_types;
|
||||
|
||||
void error(TypeType lhs, TypeType rhs, Loc const& loc);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -27,7 +27,6 @@ namespace grino
|
|||
entry.name = name;
|
||||
entry.is_object = false;
|
||||
entry.scope = scope;
|
||||
|
||||
m_entries.push_back(entry);
|
||||
}
|
||||
|
||||
|
@ -40,6 +39,16 @@ namespace grino
|
|||
m_entries.back().is_object = true;
|
||||
}
|
||||
|
||||
void SymTable::declare_function(Loc const& loc,
|
||||
std::string const& name,
|
||||
size_t addr,
|
||||
size_t scope,
|
||||
std::shared_ptr<Prototype> prototype)
|
||||
{
|
||||
declare_object(loc, name, addr, scope);
|
||||
m_entries.back().prototype = prototype;
|
||||
}
|
||||
|
||||
std::optional<SymEntry> SymTable::find(std::string const& name, size_t scope)
|
||||
{
|
||||
std::optional<SymEntry> entry;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "commons.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "types.hpp"
|
||||
#include "Prototype.hpp"
|
||||
|
||||
namespace grino
|
||||
{
|
||||
|
@ -11,6 +13,7 @@ namespace grino
|
|||
bool is_object; /* object are on the heap instead of the stack */
|
||||
size_t addr; /* address on the heap if object, local address otherwise */
|
||||
size_t scope;
|
||||
std::shared_ptr<Prototype> prototype; /* only used by functions */
|
||||
};
|
||||
|
||||
GRINO_ERROR(symbolic_error);
|
||||
|
@ -27,6 +30,9 @@ namespace grino
|
|||
void declare_object(Loc const& loc, std::string const& name, size_t addr,
|
||||
size_t scope);
|
||||
|
||||
void declare_function(Loc const& loc, std::string const& name, size_t addr,
|
||||
size_t scope, std::shared_ptr<Prototype> prototype);
|
||||
|
||||
std::optional<SymEntry> find(std::string const& name, size_t scope);
|
||||
std::optional<SymEntry> find_no_scope(std::string const& name);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "VM.hpp"
|
||||
#include "src/Value.hpp"
|
||||
#include "Value.hpp"
|
||||
#include "Module.hpp"
|
||||
#include "src/opcodes.hpp"
|
||||
#include "opcodes.hpp"
|
||||
#include <optional>
|
||||
|
||||
namespace grino
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "Value.hpp"
|
||||
#include "Program.hpp"
|
||||
#include "src/types.hpp"
|
||||
#include "types.hpp"
|
||||
#include "Module.hpp"
|
||||
|
||||
namespace grino
|
||||
|
@ -37,23 +37,28 @@ namespace grino
|
|||
}
|
||||
|
||||
/*static*/
|
||||
std::shared_ptr<Value> Value::make_native_function(Loc const& loc,
|
||||
native_t val)
|
||||
std::shared_ptr<Value>
|
||||
Value::make_native_function(Loc const& loc,
|
||||
native_t val,
|
||||
std::shared_ptr<Prototype> prototype)
|
||||
{
|
||||
auto value = std::make_shared<Value>(loc);
|
||||
value->m_type = TYPE_FUNCTION;
|
||||
value->m_function_val = std::make_shared<Function>(val);
|
||||
value->m_function_val->set_prototype(prototype);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<Value>
|
||||
Value::make_function(Loc const& loc,
|
||||
std::shared_ptr<Program> val,
|
||||
size_t base_addr)
|
||||
size_t base_addr,
|
||||
std::shared_ptr<Prototype> prototype)
|
||||
{
|
||||
auto value = std::make_shared<Value>(loc);
|
||||
value->m_type = TYPE_FUNCTION;
|
||||
value->m_function_val = std::make_shared<Function>(val, base_addr);
|
||||
value->m_function_val->set_prototype(prototype);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,17 @@ namespace grino
|
|||
static std::shared_ptr<Value> make_bool(Loc const& loc, bool val);
|
||||
static std::shared_ptr<Value> make_int(Loc const& loc, int val);
|
||||
static std::shared_ptr<Value> make_float(Loc const& loc, float val);
|
||||
static std::shared_ptr<Value> make_native_function(Loc const& loc,
|
||||
native_t val);
|
||||
static std::shared_ptr<Value> make_function(Loc const& loc,
|
||||
std::shared_ptr<Program> val,
|
||||
size_t base_addr);
|
||||
|
||||
static std::shared_ptr<Value>
|
||||
make_native_function(Loc const& loc,
|
||||
native_t val,
|
||||
std::shared_ptr<Prototype> prototype=nullptr);
|
||||
|
||||
static std::shared_ptr<Value>
|
||||
make_function(Loc const& loc,
|
||||
std::shared_ptr<Program> val,
|
||||
size_t base_addr,
|
||||
std::shared_ptr<Prototype> prototype=nullptr);
|
||||
|
||||
static std::shared_ptr<Value> make_ref(Loc const& loc,
|
||||
size_t val);
|
||||
|
|
111
src/main.cpp
111
src/main.cpp
|
@ -8,12 +8,14 @@
|
|||
#include "Program.hpp"
|
||||
#include "VM.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "src/SymTable.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "Loader.hpp"
|
||||
#include "Addr.hpp"
|
||||
#include "StaticPass.hpp"
|
||||
|
||||
|
||||
void run(char* const source_name, bool debug_mode)
|
||||
void run(char* const source_name,
|
||||
std::vector<std::filesystem::path> const& libs,
|
||||
bool debug_mode)
|
||||
{
|
||||
std::string source;
|
||||
{
|
||||
|
@ -51,12 +53,16 @@ void run(char* const source_name, bool debug_mode)
|
|||
grino::Compiler compiler {logger, addr};
|
||||
|
||||
grino::Loader loader {vm, compiler, sym_table};
|
||||
|
||||
for (auto p: libs)
|
||||
{
|
||||
loader.add_lib(p);
|
||||
}
|
||||
|
||||
loader.load_libraries();
|
||||
|
||||
for (auto dep: loader.dependencies(ast))
|
||||
{
|
||||
// TODO: import them
|
||||
}
|
||||
grino::StaticPass static_pass {logger, compiler, sym_table};
|
||||
static_pass.check(ast);
|
||||
|
||||
compiler.compile(ast, program, sym_table);
|
||||
|
||||
|
@ -78,55 +84,80 @@ void run(char* const source_name, bool debug_mode)
|
|||
int main(int argc, char** argv)
|
||||
{
|
||||
bool debug_mode = false;
|
||||
std::vector<std::filesystem::path> libs;
|
||||
|
||||
static struct option options[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int option_index = 0;
|
||||
|
||||
int c = getopt_long(argc, argv, "hvd", options, &option_index);
|
||||
|
||||
switch (c)
|
||||
while (true)
|
||||
{
|
||||
case 'h': {
|
||||
std::cout << "Usage: grino [OPTION]... source" << std::endl;
|
||||
std::cout << "OPTIONS:" << std::endl;
|
||||
std::cout << "\t" << "-d, --debug, "
|
||||
<< "activate debug mode" << std::endl;
|
||||
static struct option options[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"lib", no_argument, 0, 'l'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
std::cout << "\t" << "-h, --help, "
|
||||
<< "show this message" << std::endl;
|
||||
std::cout << "\t" << "-v, --version, "
|
||||
<< "show grino version" << std::endl;
|
||||
exit(0);
|
||||
} break;
|
||||
int option_index = 0;
|
||||
|
||||
case 'v': {
|
||||
std::cout << "grino version: " << GRINO_VERSION << std::endl;
|
||||
std::cout << "License: " << "GPLv3 or later (see LICENSE)"<< std::endl;
|
||||
exit(0);
|
||||
} break;
|
||||
int c = getopt_long(argc, argv, "hvdl:", options, &option_index);
|
||||
|
||||
case 'd': {
|
||||
debug_mode = true;
|
||||
} break;
|
||||
if (c == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'h': {
|
||||
std::cout << "Usage: grino [OPTION]... source" << std::endl;
|
||||
std::cout << "OPTIONS:" << std::endl;
|
||||
std::cout << "\t" << "-d, --debug, "
|
||||
<< "activate debug mode" << std::endl;
|
||||
|
||||
std::cout << "\t" << "-h, --help, "
|
||||
<< "show this message" << std::endl;
|
||||
std::cout << "\t" << "-v, --version, "
|
||||
<< "show grino version" << std::endl;
|
||||
exit(0);
|
||||
} break;
|
||||
|
||||
case 'v': {
|
||||
std::cout << "grino version: " << GRINO_VERSION << std::endl;
|
||||
std::cout << "License: " << "GPLv3 or later (see LICENSE)"<< std::endl;
|
||||
exit(0);
|
||||
} break;
|
||||
|
||||
case 'd': {
|
||||
debug_mode = true;
|
||||
} break;
|
||||
|
||||
case 'l': {
|
||||
auto path = std::filesystem::path("/usr/lib")
|
||||
/ std::filesystem::path("lib" + std::string(optarg) + ".so");
|
||||
|
||||
if (std::filesystem::is_regular_file(path))
|
||||
{
|
||||
libs.push_back(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "W: cannot find lib " << path << std::endl;
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
if (debug_mode)
|
||||
{
|
||||
run(argv[optind], debug_mode);
|
||||
run(argv[optind], libs, debug_mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
run(argv[optind], debug_mode);
|
||||
run(argv[optind], libs, debug_mode);
|
||||
}
|
||||
catch(std::exception const& err)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define grino_OPCODES_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "src/mutils.hpp"
|
||||
#include "mutils.hpp"
|
||||
|
||||
#define OPCODES(G) \
|
||||
G(OPCODE_LOAD_CONST), \
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
#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);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue