2023-09-11 10:14:01 +00:00
|
|
|
#include "../src/Loader.hpp"
|
2023-09-11 11:46:41 +00:00
|
|
|
#include "src/Logger.hpp"
|
2023-09-11 15:54:59 +00:00
|
|
|
#include "src/Value.hpp"
|
2023-09-12 10:20:29 +00:00
|
|
|
#include "src/opcodes.hpp"
|
2023-09-13 21:14:49 +00:00
|
|
|
#include "../src/Module.hpp"
|
2023-09-11 11:46:41 +00:00
|
|
|
|
|
|
|
GRINO_ERROR(assertion_error);
|
2023-09-11 10:14:01 +00:00
|
|
|
|
2023-09-13 11:45:09 +00:00
|
|
|
extern "C" void lib_collection(grino::Loader& loader)
|
2023-09-13 05:46:33 +00:00
|
|
|
{
|
|
|
|
loader.add_native("ref", [&loader](auto args){
|
|
|
|
std::vector<size_t> idxs;
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
idxs.push_back(args[i]->as_int());
|
|
|
|
}
|
|
|
|
|
2023-09-13 11:45:09 +00:00
|
|
|
if (args[0]->type() == grino::TYPE_STRING)
|
|
|
|
{
|
|
|
|
auto char_val = std::string(1, args[0]->as_string()[args[1]->as_int()]);
|
|
|
|
return grino::Value::make_string(args[0]->loc(), char_val);
|
|
|
|
}
|
|
|
|
|
2023-09-13 05:46:33 +00:00
|
|
|
std::function<std::shared_ptr<grino::Value>
|
|
|
|
(std::shared_ptr<grino::Value>, std::vector<size_t>)>
|
|
|
|
f = [&](std::shared_ptr<grino::Value> val, std::vector<size_t> indexes){
|
|
|
|
if (indexes.empty())
|
|
|
|
{
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t index = indexes[0];
|
|
|
|
std::vector<size_t> next;
|
|
|
|
|
|
|
|
for (size_t i=1; i<indexes.size(); i++)
|
|
|
|
{
|
|
|
|
next.push_back(indexes[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return f(loader.vm().heap(val->as_ref())->as_array()[index], next);
|
|
|
|
};
|
|
|
|
|
|
|
|
return f(args[0], idxs);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("empty?", [&loader](auto args){
|
2023-09-13 11:45:09 +00:00
|
|
|
auto val = args[0];
|
|
|
|
if (val->type() == grino::TYPE_STRING)
|
|
|
|
{
|
|
|
|
std::string str = val->as_string();
|
|
|
|
return grino::Value::make_bool(val->loc(), str.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ref = val->as_ref();
|
2023-09-13 05:46:33 +00:00
|
|
|
auto array_val = loader.vm().heap(ref);
|
|
|
|
auto& array = array_val->as_array();
|
|
|
|
|
|
|
|
return grino::Value::make_bool(array_val->loc(), array.empty());
|
|
|
|
});
|
|
|
|
|
2023-09-13 11:45:09 +00:00
|
|
|
loader.add_native("len", [&loader](auto args){
|
|
|
|
auto val = args[0];
|
|
|
|
|
|
|
|
if (val->type() == grino::TYPE_STRING)
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(val->loc(), val->as_string().size());
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ref = val->as_ref();
|
|
|
|
auto array_val = loader.vm().heap(ref);
|
|
|
|
auto& array = array_val->as_array();
|
|
|
|
|
|
|
|
return grino::Value::make_int(array_val->loc(), array.size());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void lib_array(grino::Loader& loader)
|
|
|
|
{
|
2023-09-13 05:46:33 +00:00
|
|
|
loader.add_native("head", [&loader](auto args){
|
|
|
|
auto ref_val = args[0];
|
|
|
|
size_t ref = ref_val->as_ref();
|
|
|
|
auto array_val = loader.vm().heap(ref);
|
|
|
|
auto& array = array_val->as_array();
|
|
|
|
|
|
|
|
return array[0];
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("tail", [&loader](auto args){
|
|
|
|
auto ref_val = args[0];
|
|
|
|
size_t ref = ref_val->as_ref();
|
|
|
|
auto array_val = loader.vm().heap(ref);
|
|
|
|
auto& array = array_val->as_array();
|
|
|
|
|
|
|
|
grino::val_array_t data;
|
|
|
|
for (size_t i=1; i<array.size(); i++)
|
|
|
|
{
|
|
|
|
data.push_back(array[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto res = grino::Value::make_array(array_val->loc(), data);
|
|
|
|
size_t addr = loader.vm().heap_size();
|
|
|
|
loader.vm().set_heap(addr, res);
|
|
|
|
|
|
|
|
return grino::Value::make_ref(array_val->loc(), addr);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("cons", [&loader](auto args){
|
|
|
|
auto ref_val = args[1];
|
|
|
|
size_t ref = ref_val->as_ref();
|
|
|
|
auto array_val = loader.vm().heap(ref);
|
|
|
|
auto& array = array_val->as_array();
|
|
|
|
|
|
|
|
array.insert(std::begin(array), args[0]);
|
|
|
|
|
|
|
|
auto res = grino::Value::make_array(array_val->loc(), array);
|
|
|
|
size_t addr = loader.vm().heap_size();
|
|
|
|
loader.vm().set_heap(addr, res);
|
|
|
|
|
|
|
|
return grino::Value::make_ref(array_val->loc(), addr);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-12 04:36:55 +00:00
|
|
|
extern "C" void lib_flow_control(grino::Loader& loader)
|
|
|
|
{
|
|
|
|
loader.add_static("if", [](auto& compiler, auto node, auto& prog, auto& sym) {
|
|
|
|
auto cond_node = node->child(1).lock();
|
|
|
|
auto then_node = node->child(2).lock();
|
|
|
|
auto else_node = node->child(3).lock();
|
|
|
|
|
|
|
|
compiler.compile(cond_node, prog, sym);
|
|
|
|
size_t brf = prog.size();
|
|
|
|
prog.push_instr(grino::OPCODE_BRF, 0);
|
|
|
|
|
|
|
|
compiler.compile(then_node, prog, sym);
|
|
|
|
size_t br = prog.size();
|
|
|
|
prog.push_instr(grino::OPCODE_BR, 0);
|
|
|
|
|
|
|
|
prog.set_param(brf, prog.size());
|
|
|
|
compiler.compile(else_node, prog, sym);
|
|
|
|
|
|
|
|
prog.set_param(br, prog.size());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-11 13:59:37 +00:00
|
|
|
extern "C" void lib_int(grino::Loader& loader)
|
|
|
|
{
|
|
|
|
loader.add_native("+", [](auto args){
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
for (auto value: args)
|
|
|
|
{
|
|
|
|
result += value->as_int();
|
|
|
|
}
|
|
|
|
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("*", [](auto args){
|
|
|
|
int result = 1;
|
|
|
|
|
|
|
|
for (auto value: args)
|
|
|
|
{
|
|
|
|
result *= value->as_int();
|
|
|
|
}
|
|
|
|
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("-", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int result = args[0]->as_int();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, -result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result -= args[i]->as_int();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("/", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int result = args[0]->as_int();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result /= args[i]->as_int();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("%", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int result = args[0]->as_int();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result %= args[i]->as_int();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("^", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int result = args[0]->as_int();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result = std::pow(result, args[i]->as_int());
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-13 10:15:12 +00:00
|
|
|
extern "C" void lib_float(grino::Loader& loader)
|
|
|
|
{
|
|
|
|
loader.add_native("+.", [](auto args){
|
|
|
|
float result = 0;
|
|
|
|
|
|
|
|
for (auto value: args)
|
|
|
|
{
|
|
|
|
result += value->as_float();
|
|
|
|
}
|
|
|
|
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("*.", [](auto args){
|
|
|
|
float result = 1;
|
|
|
|
|
|
|
|
for (auto value: args)
|
|
|
|
{
|
|
|
|
result *= value->as_float();
|
|
|
|
}
|
|
|
|
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("-.", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_float(loc, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
float result = args[0]->as_float();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_float(loc, -result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result -= args[i]->as_float();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("/.", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_float(loc, 1.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
float result = args[0]->as_float();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result /= args[i]->as_float();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("%.", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_float(loc, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
float result = args[0]->as_float();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result = std::fmod(result, args[i]->as_float());
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("^.", [](auto args){
|
|
|
|
grino::Loc loc {"???", 0};
|
|
|
|
|
|
|
|
if (args.empty() == false)
|
|
|
|
{
|
|
|
|
loc = args.front()->loc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return grino::Value::make_float(loc, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
float result = args[0]->as_float();
|
|
|
|
|
|
|
|
if (args.size() == 1)
|
|
|
|
{
|
|
|
|
return grino::Value::make_int(loc, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
result = std::pow(result, args[i]->as_float());
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_float(loc, result);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-11 15:54:59 +00:00
|
|
|
extern "C" void lib_cmp(grino::Loader& loader)
|
|
|
|
{
|
|
|
|
loader.add_native("<", [](auto args){
|
2023-09-13 10:15:12 +00:00
|
|
|
if (args[0]->type() == grino::TYPE_INT)
|
|
|
|
{
|
|
|
|
int lhs = args[0]->as_int();
|
|
|
|
int rhs = args[1]->as_int();
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs < rhs);
|
|
|
|
}
|
|
|
|
else if (args[0]->type() == grino::TYPE_FLOAT)
|
|
|
|
{
|
|
|
|
float lhs = args[0]->as_float();
|
|
|
|
float rhs = args[1]->as_float();
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs < rhs);
|
|
|
|
}
|
2023-09-11 15:54:59 +00:00
|
|
|
|
2023-09-13 10:15:12 +00:00
|
|
|
assert(0);
|
2023-09-11 15:54:59 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("<=", [](auto args){
|
2023-09-13 10:15:12 +00:00
|
|
|
if (args[0]->type() == grino::TYPE_INT)
|
|
|
|
{
|
|
|
|
int lhs = args[0]->as_int();
|
|
|
|
int rhs = args[1]->as_int();
|
2023-09-11 15:54:59 +00:00
|
|
|
|
2023-09-13 10:15:12 +00:00
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs <= rhs);
|
|
|
|
}
|
|
|
|
else if (args[0]->type() == grino::TYPE_FLOAT)
|
|
|
|
{
|
|
|
|
float lhs = args[0]->as_float();
|
|
|
|
float rhs = args[1]->as_float();
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs <= rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(0);
|
2023-09-11 15:54:59 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native(">", [](auto args){
|
2023-09-13 10:15:12 +00:00
|
|
|
if (args[0]->type() == grino::TYPE_INT)
|
|
|
|
{
|
|
|
|
int lhs = args[0]->as_int();
|
|
|
|
int rhs = args[1]->as_int();
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs > rhs);
|
|
|
|
}
|
|
|
|
else if (args[0]->type() == grino::TYPE_FLOAT)
|
|
|
|
{
|
|
|
|
float lhs = args[0]->as_float();
|
|
|
|
float rhs = args[1]->as_float();
|
2023-09-11 15:54:59 +00:00
|
|
|
|
2023-09-13 10:15:12 +00:00
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs > rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(0);
|
2023-09-11 15:54:59 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native(">=", [](auto args){
|
2023-09-13 10:15:12 +00:00
|
|
|
if (args[0]->type() == grino::TYPE_INT)
|
|
|
|
{
|
|
|
|
int lhs = args[0]->as_int();
|
|
|
|
int rhs = args[1]->as_int();
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs >= rhs);
|
|
|
|
}
|
|
|
|
else if (args[0]->type() == grino::TYPE_FLOAT)
|
|
|
|
{
|
|
|
|
float lhs = args[0]->as_float();
|
|
|
|
float rhs = args[1]->as_float();
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args[0]->loc(), lhs >= rhs);
|
|
|
|
}
|
2023-09-11 15:54:59 +00:00
|
|
|
|
2023-09-13 10:15:12 +00:00
|
|
|
assert(0);
|
2023-09-11 15:54:59 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("ne?", [](auto args){
|
2023-09-13 10:15:12 +00:00
|
|
|
auto lhs = args[0];
|
|
|
|
auto rhs = args[1];
|
2023-09-11 15:54:59 +00:00
|
|
|
|
2023-09-13 10:15:12 +00:00
|
|
|
return grino::Value::make_bool(args[0]->loc(), !lhs->equals(*rhs));
|
2023-09-11 15:54:59 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
});
|
|
|
|
|
2023-09-11 18:59:54 +00:00
|
|
|
loader.add_static("and", [](auto& compiler, auto node,
|
|
|
|
auto& program,
|
|
|
|
auto& sym){
|
2023-09-11 15:54:59 +00:00
|
|
|
std::vector<size_t> to_false;
|
|
|
|
|
|
|
|
for (size_t i=1; i<node->size(); i++)
|
|
|
|
{
|
2023-09-11 18:59:54 +00:00
|
|
|
compiler.compile(node->child(i).lock(), program, sym);
|
2023-09-11 15:54:59 +00:00
|
|
|
to_false.push_back(program.size());
|
|
|
|
program.push_instr(grino::OPCODE_BRF, 0 /* to false */);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t addr = program
|
|
|
|
.push_constant(grino::Value::make_bool(node->loc(), true));
|
|
|
|
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
|
|
|
size_t to_end = program.size();
|
|
|
|
program.push_instr(grino::OPCODE_BR, 0 /* to end */);
|
|
|
|
|
|
|
|
for (auto a: to_false)
|
|
|
|
{
|
|
|
|
program.set_param(a, program.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = program
|
|
|
|
.push_constant(grino::Value::make_bool(node->loc(), false));
|
|
|
|
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
|
|
|
|
|
|
|
program.set_param(to_end, program.size());
|
|
|
|
});
|
|
|
|
|
2023-09-11 18:59:54 +00:00
|
|
|
loader.add_static("or", [](auto& compiler, auto node,
|
|
|
|
auto& program, auto& sym){
|
2023-09-11 15:54:59 +00:00
|
|
|
std::vector<size_t> to_true;
|
|
|
|
|
|
|
|
for (size_t i=1; i<node->size(); i++)
|
|
|
|
{
|
2023-09-11 18:59:54 +00:00
|
|
|
compiler.compile(node->child(i).lock(), program, sym);
|
2023-09-11 15:54:59 +00:00
|
|
|
program.push_instr(grino::OPCODE_NOT);
|
|
|
|
to_true.push_back(program.size());
|
|
|
|
program.push_instr(grino::OPCODE_BRF, 0 /* to true */);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t addr = program
|
|
|
|
.push_constant(grino::Value::make_bool(node->loc(), false));
|
|
|
|
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
|
|
|
size_t to_end = program.size();
|
|
|
|
program.push_instr(grino::OPCODE_BR, 0 /* to end */);
|
|
|
|
|
|
|
|
for (auto a: to_true)
|
|
|
|
{
|
|
|
|
program.set_param(a, program.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = program
|
|
|
|
.push_constant(grino::Value::make_bool(node->loc(), true));
|
|
|
|
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
|
|
|
|
|
|
|
|
program.set_param(to_end, program.size());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-11 12:05:10 +00:00
|
|
|
extern "C" void lib_assert(grino::Loader& loader)
|
|
|
|
{
|
2023-09-11 13:59:37 +00:00
|
|
|
loader.add_native("assert", [](auto args){
|
2023-09-11 12:05:10 +00:00
|
|
|
|
|
|
|
for (auto value: args)
|
|
|
|
{
|
|
|
|
if (!value->as_bool())
|
|
|
|
{
|
|
|
|
grino::Logger logger;
|
|
|
|
logger.log<assertion_error>(grino::LOG_ASSERT,
|
|
|
|
value->loc(),
|
|
|
|
"assertion failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args.front()->loc(), true);
|
|
|
|
});
|
|
|
|
|
2023-09-13 09:33:57 +00:00
|
|
|
loader.add_native("assert=", [](auto args){
|
2023-09-11 12:05:10 +00:00
|
|
|
auto lhs = args.front();
|
|
|
|
|
|
|
|
for (size_t i=1; i<args.size(); i++)
|
|
|
|
{
|
|
|
|
auto rhs = args[i];
|
|
|
|
|
|
|
|
if (!lhs->equals(*rhs))
|
|
|
|
{
|
|
|
|
grino::Logger logger;
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
ss << "'" << lhs->string() << "' is not equals to '"
|
|
|
|
<< rhs->string() << "'";
|
|
|
|
|
|
|
|
logger.log<assertion_error>(grino::LOG_ASSERT,
|
|
|
|
lhs->loc(),
|
|
|
|
ss.str());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args.front()->loc(), true);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-13 11:45:09 +00:00
|
|
|
extern "C" void lib_string(grino::Loader& loader)
|
|
|
|
{
|
|
|
|
loader.add_native("dup", [](auto args) {
|
|
|
|
std::string value = args[0]->as_string();
|
|
|
|
size_t count = args[1]->as_int();
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
for (size_t i=0; i<count; i++)
|
|
|
|
{
|
|
|
|
result += value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_string(args[0]->loc(), result);
|
|
|
|
});
|
|
|
|
|
|
|
|
loader.add_native("cat", [](auto args) {
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
for (auto arg: args)
|
|
|
|
{
|
|
|
|
result += arg->as_string();
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_string(args[0]->loc(), result);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-11 10:14:01 +00:00
|
|
|
extern "C" void lib(grino::Loader& loader)
|
|
|
|
{
|
2023-09-11 12:05:10 +00:00
|
|
|
lib_assert(loader);
|
2023-09-11 13:59:37 +00:00
|
|
|
lib_int(loader);
|
2023-09-13 10:15:12 +00:00
|
|
|
lib_float(loader);
|
2023-09-11 15:54:59 +00:00
|
|
|
lib_cmp(loader);
|
|
|
|
lib_bool(loader);
|
2023-09-12 04:36:55 +00:00
|
|
|
lib_flow_control(loader);
|
2023-09-13 11:45:09 +00:00
|
|
|
lib_collection(loader);
|
2023-09-13 05:46:33 +00:00
|
|
|
lib_array(loader);
|
2023-09-13 11:45:09 +00:00
|
|
|
lib_string(loader);
|
2023-09-11 12:05:10 +00:00
|
|
|
|
2023-09-11 10:14:01 +00:00
|
|
|
loader.add_native("dump", [](auto args){
|
|
|
|
std::string sep;
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
for (auto arg: args)
|
|
|
|
{
|
|
|
|
ss << sep << arg->string();
|
|
|
|
sep = " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << ss.str() << std::endl;
|
|
|
|
|
2023-09-11 11:46:41 +00:00
|
|
|
return grino::Value::make_nil(args.back()->loc());
|
|
|
|
});
|
|
|
|
|
2023-09-12 10:20:29 +00:00
|
|
|
loader.add_static("set!", [](auto& compiler,
|
|
|
|
auto node,
|
|
|
|
auto& program,
|
|
|
|
auto& sym){
|
|
|
|
std::string ident = node->child(1).lock()->repr();
|
|
|
|
auto expr = node->child(2).lock();
|
|
|
|
|
|
|
|
auto entry = sym.find(ident, compiler.scope());
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
{
|
|
|
|
compiler.compile(expr, program, sym);
|
2023-09-12 19:11:29 +00:00
|
|
|
program.push_instr(grino::OPCODE_STORE_LOCAL, entry->addr);
|
2023-09-12 10:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
program.push_value(grino::Value::make_nil(node->loc()));
|
|
|
|
});
|
|
|
|
|
2023-09-11 12:05:10 +00:00
|
|
|
loader.add_native("eq?", [](auto args){
|
|
|
|
auto lhs = args.front();
|
2023-09-11 11:46:41 +00:00
|
|
|
|
2023-09-11 12:05:10 +00:00
|
|
|
for (size_t i=1; i<args.size(); i++)
|
2023-09-11 11:46:41 +00:00
|
|
|
{
|
2023-09-11 12:05:10 +00:00
|
|
|
auto rhs = args[i];
|
|
|
|
|
|
|
|
if (!lhs->equals(*rhs))
|
2023-09-11 11:46:41 +00:00
|
|
|
{
|
2023-09-11 12:05:10 +00:00
|
|
|
return grino::Value::make_bool(rhs->loc(), false);
|
2023-09-11 11:46:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return grino::Value::make_bool(args.front()->loc(), true);
|
2023-09-11 10:14:01 +00:00
|
|
|
});
|
|
|
|
}
|