#include "../src/Loader.hpp" #include "src/Logger.hpp" #include "src/Value.hpp" #include "src/opcodes.hpp" GRINO_ERROR(assertion_error); 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()); }); } 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; ias_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; ias_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; ias_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; ias_int()); } return grino::Value::make_int(loc, result); }); } extern "C" void lib_cmp(grino::Loader& loader) { loader.add_native("<", [](auto args){ int lhs = args[0]->as_int(); int rhs = args[1]->as_int(); return grino::Value::make_bool(args[0]->loc(), lhs < rhs); }); loader.add_native("<=", [](auto args){ int lhs = args[0]->as_int(); int rhs = args[1]->as_int(); return grino::Value::make_bool(args[0]->loc(), lhs <= rhs); }); loader.add_native(">", [](auto args){ int lhs = args[0]->as_int(); int rhs = args[1]->as_int(); return grino::Value::make_bool(args[0]->loc(), lhs > rhs); }); loader.add_native(">=", [](auto args){ int lhs = args[0]->as_int(); int rhs = args[1]->as_int(); return grino::Value::make_bool(args[0]->loc(), lhs >= rhs); }); loader.add_native("ne?", [](auto args){ int lhs = args[0]->as_int(); int rhs = args[1]->as_int(); return grino::Value::make_bool(args[0]->loc(), lhs != rhs); }); } 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()); }); loader.add_static("and", [](auto& compiler, auto node, auto& program, auto& sym){ std::vector to_false; for (size_t i=1; isize(); i++) { compiler.compile(node->child(i).lock(), program, sym); 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()); }); loader.add_static("or", [](auto& compiler, auto node, auto& program, auto& sym){ std::vector to_true; for (size_t i=1; isize(); i++) { compiler.compile(node->child(i).lock(), program, sym); 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()); }); } extern "C" void lib_assert(grino::Loader& loader) { loader.add_native("assert", [](auto args){ for (auto value: args) { if (!value->as_bool()) { grino::Logger logger; logger.log(grino::LOG_ASSERT, value->loc(), "assertion failed"); } } return grino::Value::make_bool(args.front()->loc(), true); }); loader.add_native("assert-eq?", [](auto args){ auto lhs = args.front(); for (size_t i=1; iequals(*rhs)) { grino::Logger logger; std::stringstream ss; ss << "'" << lhs->string() << "' is not equals to '" << rhs->string() << "'"; logger.log(grino::LOG_ASSERT, lhs->loc(), ss.str()); } } return grino::Value::make_bool(args.front()->loc(), true); }); } extern "C" void lib(grino::Loader& loader) { lib_assert(loader); lib_int(loader); lib_cmp(loader); lib_bool(loader); lib_flow_control(loader); 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; return grino::Value::make_nil(args.back()->loc()); }); 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); program.push_instr(grino::OPCODE_STORE_LOCAL, entry->addr); } program.push_value(grino::Value::make_nil(node->loc())); }); loader.add_native("eq?", [](auto args){ auto lhs = args.front(); for (size_t i=1; iequals(*rhs)) { return grino::Value::make_bool(rhs->loc(), false); } } return grino::Value::make_bool(args.front()->loc(), true); }); }