From 59af9d809e6a6afbd71a382f650292d085ce466c Mon Sep 17 00:00:00 2001 From: bog Date: Mon, 11 Sep 2023 17:54:59 +0200 Subject: [PATCH] ADD: bool arithmetic and comparison operators. --- examples/bool.gri | 19 ++++++++ examples/int.gri | 19 ++++++++ lib/core.cpp | 105 +++++++++++++++++++++++++++++++++++++++++ meson.build | 1 + src/Compiler.cpp | 24 ++++++++-- src/Compiler.hpp | 6 +++ src/Loader.cpp | 8 +++- src/Loader.hpp | 7 ++- src/Program.cpp | 7 +++ src/Program.hpp | 2 + src/StaticFunction.cpp | 21 +++++++++ src/StaticFunction.hpp | 29 ++++++++++++ src/VM.cpp | 25 ++++++++++ src/main.cpp | 4 +- src/opcodes.hpp | 3 ++ 15 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 examples/bool.gri create mode 100644 src/StaticFunction.cpp create mode 100644 src/StaticFunction.hpp diff --git a/examples/bool.gri b/examples/bool.gri new file mode 100644 index 0000000..822254b --- /dev/null +++ b/examples/bool.gri @@ -0,0 +1,19 @@ +(assert-eq? false (not true)) +(assert-eq? true (not false)) +(assert-eq? false (not (not false))) + +(assert-eq? true (and true true)) +(assert-eq? false (and true false)) +(assert-eq? false (and false true)) +(assert-eq? false (and false false)) + +(assert-eq? true (and true true true true true)) +(assert-eq? false (and true true true true false)) + +(assert-eq? true (or true true)) +(assert-eq? true (or true true)) +(assert-eq? true (or true true)) +(assert-eq? false (or false false)) + +(assert-eq? false (or false false false false false)) +(assert-eq? true (or false false true false false)) \ No newline at end of file diff --git a/examples/int.gri b/examples/int.gri index 521c083..acae66d 100644 --- a/examples/int.gri +++ b/examples/int.gri @@ -26,3 +26,22 @@ (assert-eq? 2 (^ 2)) (assert-eq? 8 (^ 2 3)) (assert-eq? 64 (^ 2 3 2)) + +(assert-eq? true (< 5 10)) +(assert-eq? false (< 5 5)) +(assert-eq? false (< 5 3)) + +(assert-eq? true (<= 5 10)) +(assert-eq? true (<= 5 5)) +(assert-eq? false (<= 5 3)) + +(assert-eq? true (> 15 10)) +(assert-eq? false (> 15 15)) +(assert-eq? false (> 15 37)) + +(assert-eq? true (>= 15 10)) +(assert-eq? true (>= 15 15)) +(assert-eq? false (>= 15 37)) + +(assert-eq? true (ne? 5 8)) +(assert-eq? false (ne? 5 5)) diff --git a/lib/core.cpp b/lib/core.cpp index bc16b21..2c74d51 100644 --- a/lib/core.cpp +++ b/lib/core.cpp @@ -1,5 +1,6 @@ #include "../src/Loader.hpp" #include "src/Logger.hpp" +#include "src/Value.hpp" GRINO_ERROR(assertion_error); @@ -150,6 +151,108 @@ extern "C" void lib_int(grino::Loader& loader) }); } +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){ + std::vector to_false; + + for (size_t i=1; isize(); i++) + { + compiler.compile(node->child(i).lock(), program); + 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){ + std::vector to_true; + + for (size_t i=1; isize(); i++) + { + compiler.compile(node->child(i).lock(), program); + 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){ @@ -198,6 +301,8 @@ extern "C" void lib(grino::Loader& loader) { lib_assert(loader); lib_int(loader); + lib_cmp(loader); + lib_bool(loader); loader.add_native("dump", [](auto args){ std::string sep; diff --git a/meson.build b/meson.build index 9641ad9..3ab52f5 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,7 @@ grino_src = static_library('grino', 'src/VM.cpp', 'src/Value.cpp', 'src/Function.cpp', + 'src/StaticFunction.cpp', 'src/SymTable.cpp', 'src/Loader.cpp', ]) diff --git a/src/Compiler.cpp b/src/Compiler.cpp index 7277667..3e1bd4a 100644 --- a/src/Compiler.cpp +++ b/src/Compiler.cpp @@ -2,6 +2,7 @@ #include "Program.hpp" #include "SymTable.hpp" #include "src/opcodes.hpp" +#include "StaticFunction.hpp" namespace grino { @@ -29,13 +30,24 @@ namespace grino } break; case NODE_FUNCALL: { + std::string ident = node->child(0).lock()->repr(); - for (size_t i=0; isize(); i++) + if (auto itr = m_statics.find(ident); + itr != std::end(m_statics)) { - compile(node->child(i).lock(), program); + auto fun = itr->second; + fun->call(*this, node, program); + } + else + { + for (size_t i=0; isize(); i++) + { + compile(node->child(i).lock(), program); + } + + program.push_instr(OPCODE_CALL, node->size() - 1); } - program.push_instr(OPCODE_CALL, node->size() - 1); } break; case NODE_BOOL: { @@ -94,6 +106,12 @@ namespace grino } } + void Compiler::add_static_func(std::string const& name, + std::shared_ptr fun) + { + m_statics[name] = fun; + } + size_t Compiler::get_local_address() { static size_t addr = 0; diff --git a/src/Compiler.hpp b/src/Compiler.hpp index 166c7fa..7c11dbf 100644 --- a/src/Compiler.hpp +++ b/src/Compiler.hpp @@ -10,6 +10,7 @@ namespace grino { class Program; class SymTable; + class StaticFunction; GRINO_ERROR(compile_error); @@ -22,9 +23,14 @@ namespace grino void compile(std::shared_ptr node, Program& program); + void add_static_func(std::string const& name, + std::shared_ptr fun); + private: Logger& m_logger; SymTable& m_sym; + std::unordered_map> m_statics; size_t get_local_address(); }; diff --git a/src/Loader.cpp b/src/Loader.cpp index 157f764..b3be7ea 100644 --- a/src/Loader.cpp +++ b/src/Loader.cpp @@ -5,8 +5,9 @@ namespace grino { - /*explicit*/ Loader::Loader(VM& vm, SymTable& sym_table) + /*explicit*/ Loader::Loader(VM& vm, Compiler& compiler, SymTable& sym_table) : m_vm { vm } + , m_compiler { compiler } , m_sym_table { sym_table } { } @@ -44,4 +45,9 @@ namespace grino m_vm.set_heap(addr, grino::Value::make_native_function(loc, native)); m_sym_table.declare_object(loc, name, addr); } + + void Loader::add_static(std::string const& name, static_fun_t fun) + { + m_compiler.add_static_func(name, std::make_shared(fun)); + } } diff --git a/src/Loader.hpp b/src/Loader.hpp index 4f99d94..944d235 100644 --- a/src/Loader.hpp +++ b/src/Loader.hpp @@ -4,21 +4,26 @@ #include "commons.hpp" #include "VM.hpp" #include "SymTable.hpp" +#include "Compiler.hpp" +#include "StaticFunction.hpp" namespace grino { class Loader { public: - explicit Loader(VM& vm, SymTable& sym_table); + explicit Loader(VM& vm, Compiler& compiler, SymTable& sym_table); virtual ~Loader(); void load_libraries(); void load_library(std::filesystem::path path); + void add_native(std::string const& name, native_t native); + void add_static(std::string const& name, static_fun_t fun); private: VM& m_vm; + Compiler& m_compiler; SymTable& m_sym_table; }; } diff --git a/src/Program.cpp b/src/Program.cpp index 48d214e..c76053c 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -17,6 +17,12 @@ namespace grino return m_instrs[index]; } + void Program::set_param(size_t addr, size_t param) + { + assert(addr < size()); + m_instrs[addr].param = param; + } + size_t Program::push_instr(OpcodeType opcode, std::optional param /*=std::nullopt*/) { @@ -63,6 +69,7 @@ namespace grino } ss << "\n"; + addr++; } addr = 0; diff --git a/src/Program.hpp b/src/Program.hpp index fc17af3..7caf4ac 100644 --- a/src/Program.hpp +++ b/src/Program.hpp @@ -23,6 +23,8 @@ namespace grino Instr get(size_t index) const; + void set_param(size_t addr, size_t param); + size_t push_instr(OpcodeType opcode, std::optional param=std::nullopt); diff --git a/src/StaticFunction.cpp b/src/StaticFunction.cpp new file mode 100644 index 0000000..cb73e6d --- /dev/null +++ b/src/StaticFunction.cpp @@ -0,0 +1,21 @@ +#include "StaticFunction.hpp" +#include "Compiler.hpp" + +namespace grino +{ + /*explicit*/ StaticFunction::StaticFunction(static_fun_t fun) + : m_fun { fun } + { + } + + /*virtual*/ StaticFunction::~StaticFunction() + { + } + + void StaticFunction::call(Compiler& compiler, + node_t node, + prog_t prog) + { + m_fun(compiler, node, prog); + } +} diff --git a/src/StaticFunction.hpp b/src/StaticFunction.hpp new file mode 100644 index 0000000..3d76886 --- /dev/null +++ b/src/StaticFunction.hpp @@ -0,0 +1,29 @@ +#ifndef grino_STATICFUNCTION_HPP +#define grino_STATICFUNCTION_HPP + +#include "commons.hpp" +#include "Function.hpp" +#include "Node.hpp" +#include "Program.hpp" + +namespace grino +{ + class Compiler; + using node_t = std::shared_ptr; + using prog_t = Program&; + using static_fun_t = std::function; + + class StaticFunction + { + public: + explicit StaticFunction(static_fun_t fun); + virtual ~StaticFunction(); + + void call(Compiler& compiler, node_t node, prog_t prog); + + private: + static_fun_t m_fun; + }; +} + +#endif diff --git a/src/VM.cpp b/src/VM.cpp index 7819cce..743d508 100644 --- a/src/VM.cpp +++ b/src/VM.cpp @@ -25,6 +25,31 @@ namespace grino switch (instr.opcode) { + case OPCODE_NOT: { + auto val = program.constant(pop()); + push(program.push_constant(Value::make_bool(val->loc(), + !val->as_bool()))); + m_pc++; + } break; + + case OPCODE_BR: { + m_pc = *instr.param; + } break; + + case OPCODE_BRF: { + auto val = program.constant(pop())->as_bool(); + size_t addr = *instr.param; + + if (!val) + { + m_pc = addr; + } + else + { + m_pc++; + } + } break; + case OPCODE_LOAD_CONST: { push(*instr.param); m_pc++; diff --git a/src/main.cpp b/src/main.cpp index 881b259..09731c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,11 +37,11 @@ void run(char** argv, bool debug_mode) grino::SymTable sym_table {logger}; grino::VM vm {logger}; + grino::Compiler compiler {logger, sym_table}; - grino::Loader loader {vm, sym_table}; + grino::Loader loader {vm, compiler, sym_table}; loader.load_libraries(); - grino::Compiler compiler {logger, sym_table}; grino::Program program; compiler.compile(ast, program); diff --git a/src/opcodes.hpp b/src/opcodes.hpp index 9ad6f2c..1211d82 100644 --- a/src/opcodes.hpp +++ b/src/opcodes.hpp @@ -12,6 +12,9 @@ G(OPCODE_LOAD_OBJ), \ G(OPCODE_STORE_OBJ), \ G(OPCODE_CALL), \ + G(OPCODE_BRF), \ + G(OPCODE_BR), \ + G(OPCODE_NOT), \ G(OPCODE_RET), namespace grino