Compare commits
4 Commits
47b44d3439
...
e12ff96943
Author | SHA1 | Date |
---|---|---|
bog | e12ff96943 | |
bog | 29facf1647 | |
bog | 64d17de693 | |
bog | c94bf181fd |
|
@ -24,4 +24,5 @@ BLOCK ::= opar colon EXPR* cpar
|
||||||
ARRAY ::= osquare EXPR* csquare
|
ARRAY ::= osquare EXPR* csquare
|
||||||
IMPORT ::= opar import string cpar
|
IMPORT ::= opar import string cpar
|
||||||
SHORT_IMPORT ::= opar decl import ident string cpar
|
SHORT_IMPORT ::= opar decl import ident string cpar
|
||||||
|
SHORTER_IMPORT ::= opar decl import ident cpar
|
||||||
NS ::= ident ns ident
|
NS ::= ident ns ident
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
extern "C" void lib_cast(grino::Loader& loader)
|
||||||
|
{
|
||||||
|
grino::Loc loc {"core/casts"};
|
||||||
|
|
||||||
|
loader.add_native("stoi", [loc](auto args){
|
||||||
|
std::string value = args[0]->as_string();
|
||||||
|
return grino::Value::make_int(loc, std::stoi(value));
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("itos", [loc](auto args){
|
||||||
|
int value = args[0]->as_int();
|
||||||
|
return grino::Value::make_string(loc, std::to_string(value));
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("stof", [loc](auto args){
|
||||||
|
std::string value = args[0]->as_string();
|
||||||
|
return grino::Value::make_int(loc, std::stof(value));
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.add_native("ftos", [loc](auto args){
|
||||||
|
float value = args[0]->as_float();
|
||||||
|
return grino::Value::make_string(loc, std::to_string(value));
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include "../src/Loader.hpp"
|
||||||
|
#include "../src/Logger.hpp"
|
||||||
|
#include "../src/Value.hpp"
|
||||||
|
#include "../src/opcodes.hpp"
|
||||||
|
#include "../src/Module.hpp"
|
129
lib/core.cpp
129
lib/core.cpp
|
@ -1,8 +1,11 @@
|
||||||
#include "../src/Loader.hpp"
|
#include "../src/Loader.hpp"
|
||||||
#include "src/Logger.hpp"
|
#include "src/Logger.hpp"
|
||||||
|
#include "src/Prototype.hpp"
|
||||||
#include "src/Value.hpp"
|
#include "src/Value.hpp"
|
||||||
#include "src/opcodes.hpp"
|
#include "src/opcodes.hpp"
|
||||||
#include "../src/Module.hpp"
|
#include "../src/Module.hpp"
|
||||||
|
#include "cast.hpp"
|
||||||
|
#include "src/types.hpp"
|
||||||
|
|
||||||
GRINO_ERROR(assertion_error);
|
GRINO_ERROR(assertion_error);
|
||||||
|
|
||||||
|
@ -41,7 +44,11 @@ extern "C" void lib_collection(grino::Loader& loader)
|
||||||
};
|
};
|
||||||
|
|
||||||
return f(args[0], idxs);
|
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){
|
loader.add_native("empty?", [&loader](auto args){
|
||||||
auto val = args[0];
|
auto val = args[0];
|
||||||
|
@ -139,11 +146,21 @@ extern "C" void lib_flow_control(grino::Loader& loader)
|
||||||
compiler.compile(else_node, prog, sym);
|
compiler.compile(else_node, prog, sym);
|
||||||
|
|
||||||
prog.set_param(br, prog.size());
|
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)
|
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){
|
loader.add_native("+", [](auto args){
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
|
@ -160,7 +177,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_int(loc, result);
|
return grino::Value::make_int(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("*", [](auto args){
|
loader.add_native("*", [](auto args){
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
@ -178,7 +195,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_int(loc, result);
|
return grino::Value::make_int(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("-", [](auto args){
|
loader.add_native("-", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -205,7 +222,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_int(loc, result);
|
return grino::Value::make_int(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("/", [](auto args){
|
loader.add_native("/", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -232,7 +249,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_int(loc, result);
|
return grino::Value::make_int(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("%", [](auto args){
|
loader.add_native("%", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -259,7 +276,7 @@ extern "C" void lib_int(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_int(loc, result);
|
return grino::Value::make_int(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("^", [](auto args){
|
loader.add_native("^", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -286,11 +303,17 @@ extern "C" void lib_int(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_int(loc, result);
|
return grino::Value::make_int(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void lib_float(grino::Loader& loader)
|
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){
|
loader.add_native("+.", [](auto args){
|
||||||
float result = 0;
|
float result = 0;
|
||||||
|
|
||||||
|
@ -307,7 +330,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_float(loc, result);
|
return grino::Value::make_float(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("*.", [](auto args){
|
loader.add_native("*.", [](auto args){
|
||||||
float result = 1;
|
float result = 1;
|
||||||
|
@ -325,7 +348,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_float(loc, result);
|
return grino::Value::make_float(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("-.", [](auto args){
|
loader.add_native("-.", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -352,7 +375,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_float(loc, result);
|
return grino::Value::make_float(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("/.", [](auto args){
|
loader.add_native("/.", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -379,7 +402,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_float(loc, result);
|
return grino::Value::make_float(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("%.", [](auto args){
|
loader.add_native("%.", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -406,7 +429,7 @@ extern "C" void lib_float(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_float(loc, result);
|
return grino::Value::make_float(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("^.", [](auto args){
|
loader.add_native("^.", [](auto args){
|
||||||
grino::Loc loc {"???", 0};
|
grino::Loc loc {"???", 0};
|
||||||
|
@ -433,11 +456,18 @@ extern "C" void lib_float(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_float(loc, result);
|
return grino::Value::make_float(loc, result);
|
||||||
});
|
}, var_proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void lib_cmp(grino::Loader& loader)
|
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){
|
loader.add_native("<", [](auto args){
|
||||||
if (args[0]->type() == grino::TYPE_INT)
|
if (args[0]->type() == grino::TYPE_INT)
|
||||||
{
|
{
|
||||||
|
@ -455,7 +485,7 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("<=", [](auto args){
|
loader.add_native("<=", [](auto args){
|
||||||
if (args[0]->type() == grino::TYPE_INT)
|
if (args[0]->type() == grino::TYPE_INT)
|
||||||
|
@ -474,7 +504,7 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native(">", [](auto args){
|
loader.add_native(">", [](auto args){
|
||||||
if (args[0]->type() == grino::TYPE_INT)
|
if (args[0]->type() == grino::TYPE_INT)
|
||||||
|
@ -493,7 +523,7 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native(">=", [](auto args){
|
loader.add_native(">=", [](auto args){
|
||||||
if (args[0]->type() == grino::TYPE_INT)
|
if (args[0]->type() == grino::TYPE_INT)
|
||||||
|
@ -512,21 +542,33 @@ extern "C" void lib_cmp(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
});
|
}, var_proto);
|
||||||
|
|
||||||
loader.add_native("ne?", [](auto args){
|
loader.add_native("ne?", [](auto args){
|
||||||
auto lhs = args[0];
|
auto lhs = args[0];
|
||||||
auto rhs = args[1];
|
auto rhs = args[1];
|
||||||
|
|
||||||
return grino::Value::make_bool(args[0]->loc(), !lhs->equals(*rhs));
|
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)
|
extern "C" void lib_bool(grino::Loader& loader)
|
||||||
{
|
{
|
||||||
loader.add_native("not", [](auto args){
|
loader.add_native("not", [](auto args){
|
||||||
return grino::Value::make_bool(args[0]->loc(), !args[0]->as_bool());
|
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,
|
loader.add_static("and", [](auto& compiler, auto node,
|
||||||
auto& program,
|
auto& program,
|
||||||
|
@ -556,7 +598,14 @@ extern "C" void lib_bool(grino::Loader& loader)
|
||||||
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
||||||
|
|
||||||
program.set_param(to_end, program.size());
|
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,
|
loader.add_static("or", [](auto& compiler, auto node,
|
||||||
auto& program, auto& sym){
|
auto& program, auto& sym){
|
||||||
|
@ -586,7 +635,14 @@ extern "C" void lib_bool(grino::Loader& loader)
|
||||||
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
||||||
|
|
||||||
program.set_param(to_end, program.size());
|
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)
|
extern "C" void lib_assert(grino::Loader& loader)
|
||||||
|
@ -605,7 +661,10 @@ extern "C" void lib_assert(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_bool(args.front()->loc(), true);
|
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){
|
loader.add_native("assert=", [](auto args){
|
||||||
auto lhs = args.front();
|
auto lhs = args.front();
|
||||||
|
@ -671,6 +730,7 @@ extern "C" void lib(grino::Loader& loader)
|
||||||
lib_collection(loader);
|
lib_collection(loader);
|
||||||
lib_array(loader);
|
lib_array(loader);
|
||||||
lib_string(loader);
|
lib_string(loader);
|
||||||
|
lib_cast(loader);
|
||||||
|
|
||||||
loader.add_native("dump", [](auto args){
|
loader.add_native("dump", [](auto args){
|
||||||
std::string sep;
|
std::string sep;
|
||||||
|
@ -703,7 +763,17 @@ extern "C" void lib(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
program.push_value(grino::Value::make_nil(node->loc()));
|
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){
|
loader.add_native("eq?", [](auto args){
|
||||||
auto lhs = args.front();
|
auto lhs = args.front();
|
||||||
|
@ -719,5 +789,14 @@ extern "C" void lib(grino::Loader& loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
return grino::Value::make_bool(args.front()->loc(), true);
|
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}
|
||||||
|
}}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include "src/Loader.hpp"
|
||||||
|
#include "src/Module.hpp"
|
||||||
|
|
||||||
|
extern "C" void lib_io(grino::Loader& loader)
|
||||||
|
{
|
||||||
|
auto mod = loader.add_module("io");
|
||||||
|
|
||||||
|
mod->loader()->add_native("print", [](auto args){
|
||||||
|
for (auto arg: args)
|
||||||
|
{
|
||||||
|
std::cout << arg->string();
|
||||||
|
}
|
||||||
|
return grino::Value::make_nil(grino::Loc {"io"});
|
||||||
|
});
|
||||||
|
|
||||||
|
mod->loader()->add_native("println", [](auto args){
|
||||||
|
for (auto arg: args)
|
||||||
|
{
|
||||||
|
std::cout << arg->string();
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
return grino::Value::make_nil(grino::Loc {"io"});
|
||||||
|
});
|
||||||
|
|
||||||
|
mod->loader()->add_native("read", [](auto args){
|
||||||
|
std::string value;
|
||||||
|
std::cin >> value;
|
||||||
|
|
||||||
|
return grino::Value::make_string(grino::Loc {"io"}, value);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#include <random>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "src/Loader.hpp"
|
||||||
|
#include "src/Module.hpp"
|
||||||
|
|
||||||
|
extern "C" void lib_rand(grino::Loader& loader)
|
||||||
|
{
|
||||||
|
grino::Loc loc {"core/rand"};
|
||||||
|
auto mod = loader.add_module("rand");
|
||||||
|
|
||||||
|
mod->loader()->add_native("randf", [loc](auto args){
|
||||||
|
std::mt19937 r;
|
||||||
|
|
||||||
|
r.seed(std::chrono::steady_clock::now().time_since_epoch().count());
|
||||||
|
|
||||||
|
std::uniform_real_distribution<float> urd(0.0f, 1.0f);
|
||||||
|
|
||||||
|
return grino::Value::make_float(loc, urd(r));
|
||||||
|
});
|
||||||
|
|
||||||
|
mod->loader()->add_native("range", [loc](auto args){
|
||||||
|
std::mt19937 r;
|
||||||
|
|
||||||
|
r.seed(std::chrono::steady_clock::now().time_since_epoch().count());
|
||||||
|
int from = args[0]->as_int();
|
||||||
|
int to = args[1]->as_int();
|
||||||
|
|
||||||
|
std::uniform_int_distribution<int> dist(from, to);
|
||||||
|
|
||||||
|
return grino::Value::make_int(loc, dist(r));
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include "src/Loader.hpp"
|
||||||
|
|
||||||
|
#include "io.hpp"
|
||||||
|
#include "rand.hpp"
|
||||||
|
|
||||||
|
extern "C" void lib(grino::Loader& loader)
|
||||||
|
{
|
||||||
|
lib_io(loader);
|
||||||
|
lib_rand(loader);
|
||||||
|
}
|
15
meson.build
15
meson.build
|
@ -35,6 +35,8 @@ grino_src = shared_library('grino',
|
||||||
'src/Loader.cpp',
|
'src/Loader.cpp',
|
||||||
'src/Addr.cpp',
|
'src/Addr.cpp',
|
||||||
'src/Module.cpp',
|
'src/Module.cpp',
|
||||||
|
'src/StaticPass.cpp',
|
||||||
|
'src/Prototype.cpp',
|
||||||
],
|
],
|
||||||
install: true)
|
install: true)
|
||||||
pkg = import('pkgconfig')
|
pkg = import('pkgconfig')
|
||||||
|
@ -62,6 +64,8 @@ install_headers(
|
||||||
'src/Loader.hpp',
|
'src/Loader.hpp',
|
||||||
'src/Addr.hpp',
|
'src/Addr.hpp',
|
||||||
'src/Module.hpp',
|
'src/Module.hpp',
|
||||||
|
'src/StaticPass.hpp',
|
||||||
|
'src/Prototype.hpp',
|
||||||
], subdir: 'grino'
|
], subdir: 'grino'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,6 +81,16 @@ shared_library('grino_core',
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: grino_libdir)
|
install_dir: grino_libdir)
|
||||||
|
|
||||||
|
shared_library('grino_std',
|
||||||
|
sources: [
|
||||||
|
'lib/std/std.cpp'
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
grino_dep
|
||||||
|
],
|
||||||
|
install: true,
|
||||||
|
install_dir: grino_libdir)
|
||||||
|
|
||||||
executable('grino',
|
executable('grino',
|
||||||
sources: [
|
sources: [
|
||||||
'src/main.cpp'
|
'src/main.cpp'
|
||||||
|
@ -91,6 +105,7 @@ executable('grino-tests',
|
||||||
'tests/main.cpp',
|
'tests/main.cpp',
|
||||||
'tests/Lexer.cpp',
|
'tests/Lexer.cpp',
|
||||||
'tests/Parser.cpp',
|
'tests/Parser.cpp',
|
||||||
|
'tests/StaticPass.cpp',
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
grino_dep,
|
grino_dep,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "Module.hpp"
|
#include "Module.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
#include "src/opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
#include "StaticFunction.hpp"
|
#include "StaticFunction.hpp"
|
||||||
|
|
||||||
namespace grino
|
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,
|
void Compiler::add_static_func(std::string const& name,
|
||||||
std::shared_ptr<StaticFunction> fun)
|
std::shared_ptr<StaticFunction> fun)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "src/mutils.hpp"
|
#include "mutils.hpp"
|
||||||
#include "Addr.hpp"
|
#include "Addr.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
|
@ -27,6 +27,14 @@ namespace grino
|
||||||
Program& program,
|
Program& program,
|
||||||
SymTable& sym);
|
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,
|
void add_static_func(std::string const& name,
|
||||||
std::shared_ptr<StaticFunction> fun);
|
std::shared_ptr<StaticFunction> fun);
|
||||||
|
|
||||||
|
|
|
@ -51,4 +51,8 @@ namespace grino
|
||||||
m_env[addr] = value;
|
m_env[addr] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Function::set_prototype(std::shared_ptr<Prototype> prototype)
|
||||||
|
{
|
||||||
|
m_prototype = prototype;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define grino_FUNCTION_HPP
|
#define grino_FUNCTION_HPP
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
|
#include "Prototype.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
@ -19,6 +20,7 @@ namespace grino
|
||||||
explicit Function(std::shared_ptr<Program> prog, size_t base_addr);
|
explicit Function(std::shared_ptr<Program> prog, size_t base_addr);
|
||||||
virtual ~Function();
|
virtual ~Function();
|
||||||
|
|
||||||
|
std::shared_ptr<Prototype> prototype() const { return m_prototype; }
|
||||||
size_t base_addr() const { return m_base_addr; }
|
size_t base_addr() const { return m_base_addr; }
|
||||||
|
|
||||||
bool is_native() const;
|
bool is_native() const;
|
||||||
|
@ -29,11 +31,14 @@ namespace grino
|
||||||
std::shared_ptr<Value> env(size_t addr) const;
|
std::shared_ptr<Value> env(size_t addr) const;
|
||||||
void set_env(size_t addr, std::shared_ptr<Value> value);
|
void set_env(size_t addr, std::shared_ptr<Value> value);
|
||||||
|
|
||||||
|
void set_prototype(std::shared_ptr<Prototype> prototype);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
native_t m_native;
|
native_t m_native;
|
||||||
std::shared_ptr<Program> m_prog;
|
std::shared_ptr<Program> m_prog;
|
||||||
std::unordered_map<size_t, std::shared_ptr<Value>> m_env;
|
std::unordered_map<size_t, std::shared_ptr<Value>> m_env;
|
||||||
size_t m_base_addr = 0;
|
size_t m_base_addr = 0;
|
||||||
|
std::shared_ptr<Prototype> m_prototype;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "Lexer.hpp"
|
#include "Lexer.hpp"
|
||||||
#include "src/Node.hpp"
|
#include "Node.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "Loader.hpp"
|
#include "Loader.hpp"
|
||||||
#include "Function.hpp"
|
#include "Function.hpp"
|
||||||
#include "src/config.in.hpp"
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include "Lexer.hpp"
|
#include "Lexer.hpp"
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
|
@ -44,6 +43,11 @@ namespace grino
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Loader::add_lib(std::filesystem::path path)
|
||||||
|
{
|
||||||
|
m_libs.push_back(path);
|
||||||
|
}
|
||||||
|
|
||||||
void Loader::load_libraries()
|
void Loader::load_libraries()
|
||||||
{
|
{
|
||||||
for (auto entry: std::filesystem::directory_iterator(GRINO_LIBDIR))
|
for (auto entry: std::filesystem::directory_iterator(GRINO_LIBDIR))
|
||||||
|
@ -54,6 +58,15 @@ namespace grino
|
||||||
load_library(entry.path());
|
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)
|
void Loader::load_library(std::filesystem::path path)
|
||||||
|
@ -61,6 +74,7 @@ namespace grino
|
||||||
void* handle = dlopen(path.string().c_str(), RTLD_NOW);
|
void* handle = dlopen(path.string().c_str(), RTLD_NOW);
|
||||||
typedef void(*libfun)(Loader&);
|
typedef void(*libfun)(Loader&);
|
||||||
libfun f = (libfun) dlsym(handle, "lib");
|
libfun f = (libfun) dlsym(handle, "lib");
|
||||||
|
assert(f);
|
||||||
|
|
||||||
f(*this);
|
f(*this);
|
||||||
}
|
}
|
||||||
|
@ -88,8 +102,23 @@ namespace grino
|
||||||
m_sym_table.declare_object(loc, name, addr, 0);
|
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>
|
std::vector<std::filesystem::path>
|
||||||
dependencies(std::shared_ptr<Node> node);
|
dependencies(std::shared_ptr<Node> node);
|
||||||
|
|
||||||
|
void add_lib(std::filesystem::path path);
|
||||||
|
|
||||||
void load_libraries();
|
void load_libraries();
|
||||||
void load_library(std::filesystem::path path);
|
void load_library(std::filesystem::path path);
|
||||||
|
|
||||||
std::shared_ptr<Module> add_module(std::string const& name);
|
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);
|
||||||
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:
|
private:
|
||||||
VM& m_vm;
|
VM& m_vm;
|
||||||
Compiler& m_compiler;
|
Compiler& m_compiler;
|
||||||
SymTable& m_sym_table;
|
SymTable& m_sym_table;
|
||||||
|
std::vector<std::filesystem::path> m_libs;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace grino
|
||||||
class Loc
|
class Loc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Loc(std::filesystem::path path, int line);
|
explicit Loc(std::filesystem::path path, int line=0);
|
||||||
virtual ~Loc();
|
virtual ~Loc();
|
||||||
|
|
||||||
std::filesystem::path path() const { return m_path; }
|
std::filesystem::path path() const { return m_path; }
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define grino_LOGGER_HPP
|
#define grino_LOGGER_HPP
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "src/mutils.hpp"
|
#include "mutils.hpp"
|
||||||
#include "Loc.hpp"
|
#include "Loc.hpp"
|
||||||
|
|
||||||
#define LOG_TYPE(G) \
|
#define LOG_TYPE(G) \
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Lexer.hpp"
|
#include "Lexer.hpp"
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
#include "Compiler.hpp"
|
#include "Compiler.hpp"
|
||||||
|
#include "StaticPass.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
@ -44,6 +45,9 @@ namespace grino
|
||||||
m_loader = std::make_shared<Loader>(*m_vm, *m_compiler, *m_sym_table);
|
m_loader = std::make_shared<Loader>(*m_vm, *m_compiler, *m_sym_table);
|
||||||
m_loader->load_libraries();
|
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_compiler->compile(ast, *m_program, *m_sym_table);
|
||||||
|
|
||||||
m_vm->run();
|
m_vm->run();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
#include "src/Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "src/mutils.hpp"
|
#include "mutils.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
@ -118,7 +118,6 @@ namespace grino
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_expr()
|
std::shared_ptr<Node> Parser::parse_expr()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (type_is({NODE_IDENT, NODE_NS}))
|
if (type_is({NODE_IDENT, NODE_NS}))
|
||||||
{
|
{
|
||||||
return parse_ns();
|
return parse_ns();
|
||||||
|
@ -335,7 +334,17 @@ namespace grino
|
||||||
consume(NODE_DECL);
|
consume(NODE_DECL);
|
||||||
consume(NODE_IMPORT);
|
consume(NODE_IMPORT);
|
||||||
auto ident = consume(NODE_IDENT);
|
auto ident = consume(NODE_IDENT);
|
||||||
auto val = consume(NODE_STRING);
|
std::shared_ptr<Node> val;
|
||||||
|
|
||||||
|
if (type_is(NODE_STRING))
|
||||||
|
{
|
||||||
|
val = consume(NODE_STRING);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val = make_node(NODE_STRING, "'" + ident->repr() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
consume(NODE_CPAR);
|
consume(NODE_CPAR);
|
||||||
|
|
||||||
auto node = make_node(NODE_VARDECL);
|
auto node = make_node(NODE_VARDECL);
|
||||||
|
@ -347,5 +356,4 @@ namespace grino
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "Lexer.hpp"
|
#include "Lexer.hpp"
|
||||||
#include "src/mutils.hpp"
|
#include "mutils.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "src/opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
|
|
||||||
namespace grino
|
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
|
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_fun { fun }
|
||||||
|
, m_prototype { proto }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
|
#include "Prototype.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
@ -18,13 +19,16 @@ namespace grino
|
||||||
class StaticFunction
|
class StaticFunction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit StaticFunction(static_fun_t fun);
|
explicit StaticFunction(static_fun_t fun, std::shared_ptr<Prototype> proto);
|
||||||
virtual ~StaticFunction();
|
virtual ~StaticFunction();
|
||||||
|
|
||||||
|
std::shared_ptr<Prototype> prototype() const { return m_prototype; }
|
||||||
|
|
||||||
void call(Compiler& compiler, node_t node, prog_t prog, sym_t sym);
|
void call(Compiler& compiler, node_t node, prog_t prog, sym_t sym);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static_fun_t m_fun;
|
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.name = name;
|
||||||
entry.is_object = false;
|
entry.is_object = false;
|
||||||
entry.scope = scope;
|
entry.scope = scope;
|
||||||
|
|
||||||
m_entries.push_back(entry);
|
m_entries.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +39,16 @@ namespace grino
|
||||||
m_entries.back().is_object = true;
|
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> SymTable::find(std::string const& name, size_t scope)
|
||||||
{
|
{
|
||||||
std::optional<SymEntry> entry;
|
std::optional<SymEntry> entry;
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "Prototype.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
@ -11,6 +13,7 @@ namespace grino
|
||||||
bool is_object; /* object are on the heap instead of the stack */
|
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 addr; /* address on the heap if object, local address otherwise */
|
||||||
size_t scope;
|
size_t scope;
|
||||||
|
std::shared_ptr<Prototype> prototype; /* only used by functions */
|
||||||
};
|
};
|
||||||
|
|
||||||
GRINO_ERROR(symbolic_error);
|
GRINO_ERROR(symbolic_error);
|
||||||
|
@ -27,6 +30,9 @@ namespace grino
|
||||||
void declare_object(Loc const& loc, std::string const& name, size_t addr,
|
void declare_object(Loc const& loc, std::string const& name, size_t addr,
|
||||||
size_t scope);
|
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(std::string const& name, size_t scope);
|
||||||
std::optional<SymEntry> find_no_scope(std::string const& name);
|
std::optional<SymEntry> find_no_scope(std::string const& name);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
#include "src/Value.hpp"
|
#include "Value.hpp"
|
||||||
#include "Module.hpp"
|
#include "Module.hpp"
|
||||||
#include "src/opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
|
@ -212,7 +212,6 @@ namespace grino
|
||||||
{
|
{
|
||||||
if (fun)
|
if (fun)
|
||||||
{
|
{
|
||||||
std::cout << "store INIT" << std::endl;
|
|
||||||
fun->set_env(itr->first,
|
fun->set_env(itr->first,
|
||||||
Value::make_copy(itr->second->loc(),
|
Value::make_copy(itr->second->loc(),
|
||||||
itr->second));
|
itr->second));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "Value.hpp"
|
#include "Value.hpp"
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "src/types.hpp"
|
#include "types.hpp"
|
||||||
#include "Module.hpp"
|
#include "Module.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
|
@ -37,23 +37,28 @@ namespace grino
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/
|
/*static*/
|
||||||
std::shared_ptr<Value> Value::make_native_function(Loc const& loc,
|
std::shared_ptr<Value>
|
||||||
native_t val)
|
Value::make_native_function(Loc const& loc,
|
||||||
|
native_t val,
|
||||||
|
std::shared_ptr<Prototype> prototype)
|
||||||
{
|
{
|
||||||
auto value = std::make_shared<Value>(loc);
|
auto value = std::make_shared<Value>(loc);
|
||||||
value->m_type = TYPE_FUNCTION;
|
value->m_type = TYPE_FUNCTION;
|
||||||
value->m_function_val = std::make_shared<Function>(val);
|
value->m_function_val = std::make_shared<Function>(val);
|
||||||
|
value->m_function_val->set_prototype(prototype);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ std::shared_ptr<Value>
|
/*static*/ std::shared_ptr<Value>
|
||||||
Value::make_function(Loc const& loc,
|
Value::make_function(Loc const& loc,
|
||||||
std::shared_ptr<Program> val,
|
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);
|
auto value = std::make_shared<Value>(loc);
|
||||||
value->m_type = TYPE_FUNCTION;
|
value->m_type = TYPE_FUNCTION;
|
||||||
value->m_function_val = std::make_shared<Function>(val, base_addr);
|
value->m_function_val = std::make_shared<Function>(val, base_addr);
|
||||||
|
value->m_function_val->set_prototype(prototype);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +135,16 @@ namespace grino
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*static*/
|
||||||
|
std::shared_ptr<Value> Value::make_user_data(Loc const& loc,
|
||||||
|
void* val)
|
||||||
|
{
|
||||||
|
auto value = std::make_shared<Value>(loc);
|
||||||
|
value->m_type = TYPE_PROGRAM;
|
||||||
|
value->m_user_data_val = val;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Program> Value::as_program() const
|
std::shared_ptr<Program> Value::as_program() const
|
||||||
{
|
{
|
||||||
return m_program_val;
|
return m_program_val;
|
||||||
|
@ -152,6 +167,7 @@ namespace grino
|
||||||
case TYPE_FUNCTION: return "<function>";
|
case TYPE_FUNCTION: return "<function>";
|
||||||
case TYPE_REF: return "&" + std::to_string(*m_ref_val);
|
case TYPE_REF: return "&" + std::to_string(*m_ref_val);
|
||||||
case TYPE_PROGRAM: return "<program>";
|
case TYPE_PROGRAM: return "<program>";
|
||||||
|
case TYPE_USER_DATA: return "<user data>";
|
||||||
case TYPE_MODULE: return "<module " + m_module_val->name() + ">";
|
case TYPE_MODULE: return "<module " + m_module_val->name() + ">";
|
||||||
case TYPE_ARRAY: {
|
case TYPE_ARRAY: {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -188,6 +204,7 @@ namespace grino
|
||||||
case TYPE_REF: return *m_ref_val == *other.m_ref_val;
|
case TYPE_REF: return *m_ref_val == *other.m_ref_val;
|
||||||
case TYPE_PROGRAM: return false;
|
case TYPE_PROGRAM: return false;
|
||||||
case TYPE_MODULE: return false;
|
case TYPE_MODULE: return false;
|
||||||
|
case TYPE_USER_DATA: return m_user_data_val == other.m_user_data_val;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "cannot compare equality with value "
|
std::cerr << "cannot compare equality with 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_bool(Loc const& loc, bool val);
|
||||||
static std::shared_ptr<Value> make_int(Loc const& loc, int 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_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>
|
||||||
static std::shared_ptr<Value> make_function(Loc const& loc,
|
make_native_function(Loc const& loc,
|
||||||
std::shared_ptr<Program> val,
|
native_t val,
|
||||||
size_t base_addr);
|
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,
|
static std::shared_ptr<Value> make_ref(Loc const& loc,
|
||||||
size_t val);
|
size_t val);
|
||||||
|
@ -44,6 +50,9 @@ namespace grino
|
||||||
static std::shared_ptr<Value> make_module(Loc const& loc,
|
static std::shared_ptr<Value> make_module(Loc const& loc,
|
||||||
std::shared_ptr<Module> val);
|
std::shared_ptr<Module> val);
|
||||||
|
|
||||||
|
static std::shared_ptr<Value> make_user_data(Loc const& loc,
|
||||||
|
void* val);
|
||||||
|
|
||||||
explicit Value(Loc const& loc);
|
explicit Value(Loc const& loc);
|
||||||
virtual ~Value() = default;
|
virtual ~Value() = default;
|
||||||
|
|
||||||
|
@ -59,6 +68,7 @@ namespace grino
|
||||||
val_array_t const& as_array() const { return *m_array_val; }
|
val_array_t const& as_array() const { return *m_array_val; }
|
||||||
std::string const& as_string() const { return *m_string_val; }
|
std::string const& as_string() const { return *m_string_val; }
|
||||||
std::shared_ptr<Module> as_module() const;
|
std::shared_ptr<Module> as_module() const;
|
||||||
|
void* as_user_data() const { return m_user_data_val; }
|
||||||
|
|
||||||
std::string string() const;
|
std::string string() const;
|
||||||
bool equals(Value const& other) const;
|
bool equals(Value const& other) const;
|
||||||
|
@ -75,6 +85,7 @@ namespace grino
|
||||||
std::optional<val_array_t> m_array_val;
|
std::optional<val_array_t> m_array_val;
|
||||||
std::optional<std::string> m_string_val;
|
std::optional<std::string> m_string_val;
|
||||||
std::shared_ptr<Module> m_module_val;
|
std::shared_ptr<Module> m_module_val;
|
||||||
|
void* m_user_data_val = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
111
src/main.cpp
111
src/main.cpp
|
@ -8,12 +8,14 @@
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
#include "src/SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
#include "Loader.hpp"
|
#include "Loader.hpp"
|
||||||
#include "Addr.hpp"
|
#include "Addr.hpp"
|
||||||
|
#include "StaticPass.hpp"
|
||||||
|
|
||||||
|
void run(char* const source_name,
|
||||||
void run(char* const source_name, bool debug_mode)
|
std::vector<std::filesystem::path> const& libs,
|
||||||
|
bool debug_mode)
|
||||||
{
|
{
|
||||||
std::string source;
|
std::string source;
|
||||||
{
|
{
|
||||||
|
@ -51,12 +53,16 @@ void run(char* const source_name, bool debug_mode)
|
||||||
grino::Compiler compiler {logger, addr};
|
grino::Compiler compiler {logger, addr};
|
||||||
|
|
||||||
grino::Loader loader {vm, compiler, sym_table};
|
grino::Loader loader {vm, compiler, sym_table};
|
||||||
|
|
||||||
|
for (auto p: libs)
|
||||||
|
{
|
||||||
|
loader.add_lib(p);
|
||||||
|
}
|
||||||
|
|
||||||
loader.load_libraries();
|
loader.load_libraries();
|
||||||
|
|
||||||
for (auto dep: loader.dependencies(ast))
|
grino::StaticPass static_pass {logger, compiler, sym_table};
|
||||||
{
|
static_pass.check(ast);
|
||||||
// TODO: import them
|
|
||||||
}
|
|
||||||
|
|
||||||
compiler.compile(ast, program, sym_table);
|
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)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
bool debug_mode = false;
|
bool debug_mode = false;
|
||||||
|
std::vector<std::filesystem::path> libs;
|
||||||
|
|
||||||
static struct option options[] = {
|
while (true)
|
||||||
{"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)
|
|
||||||
{
|
{
|
||||||
case 'h': {
|
static struct option options[] = {
|
||||||
std::cout << "Usage: grino [OPTION]... source" << std::endl;
|
{"help", no_argument, 0, 'h'},
|
||||||
std::cout << "OPTIONS:" << std::endl;
|
{"version", no_argument, 0, 'v'},
|
||||||
std::cout << "\t" << "-d, --debug, "
|
{"debug", no_argument, 0, 'd'},
|
||||||
<< "activate debug mode" << std::endl;
|
{"lib", no_argument, 0, 'l'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
std::cout << "\t" << "-h, --help, "
|
int option_index = 0;
|
||||||
<< "show this message" << std::endl;
|
|
||||||
std::cout << "\t" << "-v, --version, "
|
|
||||||
<< "show grino version" << std::endl;
|
|
||||||
exit(0);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 'v': {
|
int c = getopt_long(argc, argv, "hvdl:", options, &option_index);
|
||||||
std::cout << "grino version: " << GRINO_VERSION << std::endl;
|
|
||||||
std::cout << "License: " << "GPLv3 or later (see LICENSE)"<< std::endl;
|
|
||||||
exit(0);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 'd': {
|
if (c == -1)
|
||||||
debug_mode = true;
|
{
|
||||||
} break;
|
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 (optind < argc)
|
||||||
{
|
{
|
||||||
if (debug_mode)
|
if (debug_mode)
|
||||||
{
|
{
|
||||||
run(argv[optind], debug_mode);
|
run(argv[optind], libs, debug_mode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
run(argv[optind], debug_mode);
|
run(argv[optind], libs, debug_mode);
|
||||||
}
|
}
|
||||||
catch(std::exception const& err)
|
catch(std::exception const& err)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define grino_OPCODES_HPP
|
#define grino_OPCODES_HPP
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "src/mutils.hpp"
|
#include "mutils.hpp"
|
||||||
|
|
||||||
#define OPCODES(G) \
|
#define OPCODES(G) \
|
||||||
G(OPCODE_LOAD_CONST), \
|
G(OPCODE_LOAD_CONST), \
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
G(TYPE_FLOAT), \
|
G(TYPE_FLOAT), \
|
||||||
G(TYPE_ARRAY), \
|
G(TYPE_ARRAY), \
|
||||||
G(TYPE_STRING), \
|
G(TYPE_STRING), \
|
||||||
G(TYPE_MODULE)
|
G(TYPE_MODULE), \
|
||||||
|
G(TYPE_USER_DATA)
|
||||||
|
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
|
|
|
@ -116,4 +116,10 @@ TEST_CASE_METHOD(ParserTest, "Parser_import")
|
||||||
|
|
||||||
test_parse("MODULE(VARDECL(IDENT[bim],IMPORT(STRING['hello'])))",
|
test_parse("MODULE(VARDECL(IDENT[bim],IMPORT(STRING['hello'])))",
|
||||||
"($ @bim 'hello')");
|
"($ @bim 'hello')");
|
||||||
|
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[bim],IMPORT(STRING['bim'])))",
|
||||||
|
"($ @ bim )");
|
||||||
|
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[hello_world],IMPORT(STRING['hello_world'])))",
|
||||||
|
" ( $ @ hello_world )");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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