From b1085992c829c9e540ce2b1151450547b35f9f60 Mon Sep 17 00:00:00 2001 From: bog Date: Sun, 10 Sep 2023 16:16:20 +0200 Subject: [PATCH] ADD: bool arith core functions. --- core/core.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++ lib/Compiler.cpp | 21 ++++++++++-- lib/Compiler.hpp | 7 ++++ lib/Loader.cpp | 15 +++++++-- lib/Loader.hpp | 10 ++++++ lib/Opcodes.hpp | 3 ++ lib/Program.cpp | 6 ++++ lib/Program.hpp | 2 ++ lib/StaticFunction.cpp | 20 ++++++++++++ lib/StaticFunction.hpp | 32 +++++++++++++++++++ lib/StaticPass.cpp | 32 +++++++++++++++---- lib/StaticPass.hpp | 3 ++ lib/VM.cpp | 25 +++++++++++++++ meson.build | 1 + src/main.cpp | 7 ++-- 15 files changed, 243 insertions(+), 13 deletions(-) create mode 100644 lib/StaticFunction.cpp create mode 100644 lib/StaticFunction.hpp diff --git a/core/core.cpp b/core/core.cpp index 8ba80f3..90616bb 100644 --- a/core/core.cpp +++ b/core/core.cpp @@ -1,6 +1,9 @@ #include #include "lib/Function.hpp" #include "lib/Loader.hpp" +#include "lib/Node.hpp" +#include "lib/Opcodes.hpp" +#include "lib/SymTable.hpp" #include "lib/Value.hpp" extern "C" void num_arith(jk::Loader& loader) @@ -72,9 +75,78 @@ extern "C" void num_arith(jk::Loader& loader) }); } +extern "C" void bool_arith(jk::Loader& loader) +{ + loader.declare_static("and", [loader](std::shared_ptr node, + std::shared_ptr program, + std::shared_ptr sym) { + std::vector to_false; + + for (size_t i=1; isize(); i++) + { + loader.compiler()->compile(node->child(i).lock(), program, sym); + to_false.push_back(program->size()); + program->push_instr(jk::OPCODE_BRF, 0); + } + + program->push_instr(jk::OPCODE_PUSH_CONST, + program->push_constant(jk::Value::make_bool(true))); + + size_t end = program->size(); + program->push_instr(jk::OPCODE_BR, 0); + + for (auto addr: to_false) + { + program->set_param(addr, program->size()); + } + + program->push_instr(jk::OPCODE_PUSH_CONST, + program->push_constant(jk::Value::make_bool(false))); + + program->set_param(end, program->size()); + }); + + loader.declare_static("or", [loader](std::shared_ptr node, + std::shared_ptr program, + std::shared_ptr sym) { + std::vector to_false; + + for (size_t i=1; isize(); i++) + { + loader.compiler()->compile(node->child(i).lock(), program, sym); + program->push_instr(jk::OPCODE_NOT); + to_false.push_back(program->size()); + program->push_instr(jk::OPCODE_BRF, 0); + } + + program->push_instr(jk::OPCODE_PUSH_CONST, + program->push_constant(jk::Value::make_bool(false))); + + size_t end = program->size(); + program->push_instr(jk::OPCODE_BR, 0); + + for (auto addr: to_false) + { + program->set_param(addr, program->size()); + } + + program->push_instr(jk::OPCODE_PUSH_CONST, + program->push_constant(jk::Value::make_bool(true))); + + program->set_param(end, program->size()); + }); + + loader.declare("not", [](auto args){ + auto value = args[0]->as_bool(); + return jk::Value::make_bool(!value); + }); +} + extern "C" void lib(jk::Loader& loader) { num_arith(loader); + bool_arith(loader); + loader.declare("dump", [](auto args){ std::string sep; diff --git a/lib/Compiler.cpp b/lib/Compiler.cpp index 77f7408..4d98cf3 100644 --- a/lib/Compiler.cpp +++ b/lib/Compiler.cpp @@ -1,6 +1,7 @@ #include "Compiler.hpp" #include "lib/Opcodes.hpp" #include "Code.hpp" +#include "StaticFunction.hpp" namespace jk { @@ -28,12 +29,21 @@ namespace jk } break; case NODE_FUNCALL: { - for (size_t i=0; isize(); i++) + if (auto itr=m_statics.find(node->child(0).lock()->repr()); + itr != std::end(m_statics)) { - compile(node->child(i).lock(), program, sym); + itr->second->call(node, program, sym); + } + else + { + for (size_t i=0; isize(); i++) + { + compile(node->child(i).lock(), program, sym); + } + + program->push_instr(OPCODE_CALL, node->size() - 1); } - program->push_instr(OPCODE_CALL, node->size() - 1); } break; case NODE_VARDECL: { @@ -104,4 +114,9 @@ namespace jk } } + void Compiler::declare_static(std::string const& name, + std::shared_ptr fun) + { + m_statics[name] = fun; + } } diff --git a/lib/Compiler.hpp b/lib/Compiler.hpp index 6a6a898..8ee7476 100644 --- a/lib/Compiler.hpp +++ b/lib/Compiler.hpp @@ -12,6 +12,8 @@ namespace jk { JK_ERROR(compile_error); + class StaticFunction; + class Compiler { public: @@ -22,8 +24,13 @@ namespace jk std::shared_ptr program, std::shared_ptr sym); + void declare_static(std::string const& name, + std::shared_ptr fun); + private: Logger& m_logger; + std::unordered_map> m_statics; }; } diff --git a/lib/Loader.cpp b/lib/Loader.cpp index c71c01d..3c2d18a 100644 --- a/lib/Loader.cpp +++ b/lib/Loader.cpp @@ -1,13 +1,18 @@ #include "Loader.hpp" #include "lib/Function.hpp" +#include "lib/StaticFunction.hpp" #include "lib/config.in.hpp" #include namespace jk { /*explicit*/ Loader::Loader(std::shared_ptr vm, + std::shared_ptr static_pass, + std::shared_ptr compiler, std::shared_ptr sym) : m_vm { vm } + , m_static_pass { static_pass } + , m_compiler { compiler } , m_sym { sym } { } @@ -42,9 +47,15 @@ namespace jk auto ref = Value::make_ref(addr); size_t global_addr = m_sym->declare_global(name, - fun_val->type().lock(), - Loc {"global", 1, 1}); + fun_val->type().lock(), + Loc {"global", 1, 1}); m_vm->set_global(global_addr, ref); } + void Loader::declare_static(std::string const& name, static_fun_t body) + { + m_static_pass->add_static(name); + auto fun = std::make_shared(body); + m_compiler->declare_static(name, fun); + } } diff --git a/lib/Loader.hpp b/lib/Loader.hpp index f042ef0..b5eacf7 100644 --- a/lib/Loader.hpp +++ b/lib/Loader.hpp @@ -5,6 +5,9 @@ #include "VM.hpp" #include "SymTable.hpp" #include "Function.hpp" +#include "StaticFunction.hpp" +#include "Compiler.hpp" +#include "StaticPass.hpp" namespace jk { @@ -12,14 +15,21 @@ namespace jk { public: explicit Loader(std::shared_ptr vm, + std::shared_ptr static_pass, + std::shared_ptr compiler, std::shared_ptr sym); virtual ~Loader(); + std::shared_ptr compiler() const { return m_compiler; } + void load(); void declare(std::string const& name, foreign_t body); + void declare_static(std::string const& name, static_fun_t body); private: std::shared_ptr m_vm; + std::shared_ptr m_static_pass; + std::shared_ptr m_compiler; std::shared_ptr m_sym; }; } diff --git a/lib/Opcodes.hpp b/lib/Opcodes.hpp index f23c1d9..2ece9d8 100644 --- a/lib/Opcodes.hpp +++ b/lib/Opcodes.hpp @@ -10,6 +10,9 @@ G(OPCODE_STORE), \ G(OPCODE_LOAD_GLOBAL), \ G(OPCODE_RET), \ + G(OPCODE_BRF), \ + G(OPCODE_BR), \ + G(OPCODE_NOT), \ G(OPCODE_MK_FUNCTION) namespace jk diff --git a/lib/Program.cpp b/lib/Program.cpp index a514921..08d8dbe 100644 --- a/lib/Program.cpp +++ b/lib/Program.cpp @@ -22,6 +22,12 @@ namespace jk m_instrs.push_back(Instr { opcode, param }); } + void Program::set_param(size_t index, param_t param) + { + assert(index < size()); + m_instrs[index].param = param; + } + std::string Program::string() const { std::stringstream ss; diff --git a/lib/Program.hpp b/lib/Program.hpp index e286350..29abb57 100644 --- a/lib/Program.hpp +++ b/lib/Program.hpp @@ -27,6 +27,8 @@ namespace jk void push_instr(OpcodeType opcode, std::optional param = std::nullopt); + void set_param(size_t index, param_t param); + size_t push_constant(std::shared_ptr value); std::shared_ptr constant(size_t index) const; diff --git a/lib/StaticFunction.cpp b/lib/StaticFunction.cpp new file mode 100644 index 0000000..3a8101a --- /dev/null +++ b/lib/StaticFunction.cpp @@ -0,0 +1,20 @@ +#include "StaticFunction.hpp" + +namespace jk +{ + /*explicit*/ StaticFunction::StaticFunction(static_fun_t fun) + : m_fun { fun } + { + } + + /*virtual*/ StaticFunction::~StaticFunction() + { + } + + void StaticFunction::call(std::shared_ptr node, + std::shared_ptr program, + std::shared_ptr sym) + { + m_fun(node, program, sym); + } +} diff --git a/lib/StaticFunction.hpp b/lib/StaticFunction.hpp new file mode 100644 index 0000000..14a0c34 --- /dev/null +++ b/lib/StaticFunction.hpp @@ -0,0 +1,32 @@ +#ifndef jk_STATICFUNCTION_HPP +#define jk_STATICFUNCTION_HPP + +#include "commons.hpp" +#include "Program.hpp" +#include "SymTable.hpp" +#include "Node.hpp" + +namespace jk +{ + using static_fun_t = + std::function, + std::shared_ptr, + std::shared_ptr)>; + + class StaticFunction + { + public: + explicit StaticFunction(static_fun_t fun); + virtual ~StaticFunction(); + + void call(std::shared_ptr node, + std::shared_ptr program, + std::shared_ptr sym); + + private: + static_fun_t m_fun; + }; +} + +#endif diff --git a/lib/StaticPass.cpp b/lib/StaticPass.cpp index 53b6e06..b0e5bbe 100644 --- a/lib/StaticPass.cpp +++ b/lib/StaticPass.cpp @@ -19,6 +19,7 @@ namespace jk { case NODE_PROG: case NODE_BODY: { + for (size_t i=0; isize(); i++) { pass(node->child(i).lock()); @@ -56,7 +57,9 @@ namespace jk std::string ident = node->repr(); auto entry = m_sym->find(ident); - if (!entry) + if (!entry + && std::find(std::begin(m_statics), std::end(m_statics), + ident) == std::end(m_statics)) { m_logger.log(LOG_ERROR, node->loc(), std::string() @@ -65,7 +68,10 @@ namespace jk + "' is undefined"); } - push(entry->type); + if (entry) + { + push(entry->type); + } } break; case NODE_VARDECL: { @@ -77,13 +83,22 @@ namespace jk } break; case NODE_FUNCALL: { - for (size_t i=0; isize(); i++) + auto is_static = std::find(std::begin(m_statics), + std::end(m_statics), + node->child(0).lock()->repr()) + != std::end(m_statics); + + if (!is_static) { - pass(node->child(i).lock()); - pop(); + for (size_t i=0; isize(); i++) + { + pass(node->child(i).lock()); + pop(); + } } - // TODO find actual returned type + push(std::make_shared(TYPE_NIL)); + } break; default: @@ -93,6 +108,11 @@ namespace jk } } + void StaticPass::add_static(std::string const& name) + { + m_statics.push_back(name); + } + void StaticPass::push(std::shared_ptr type) { m_types.push_back(type); diff --git a/lib/StaticPass.hpp b/lib/StaticPass.hpp index 8d00b94..21e2c36 100644 --- a/lib/StaticPass.hpp +++ b/lib/StaticPass.hpp @@ -15,10 +15,13 @@ namespace jk void pass(std::shared_ptr node); + void add_static(std::string const& name); + private: std::shared_ptr m_sym; Logger& m_logger; std::vector> m_types; + std::vector m_statics; void push(std::shared_ptr type); std::shared_ptr pop(); diff --git a/lib/VM.cpp b/lib/VM.cpp index 8a1b404..422197f 100644 --- a/lib/VM.cpp +++ b/lib/VM.cpp @@ -29,6 +29,31 @@ namespace jk switch (instr.opcode) { + case OPCODE_BRF: { + auto value = program()->constant(pop()); + + if (!value->as_bool()) + { + m_pc = *instr.param; + } + else + { + m_pc++; + } + + } break; + + case OPCODE_BR: { + m_pc = *instr.param; + } break; + + case OPCODE_NOT: { + bool value = program()->constant(pop())->as_bool(); + push(program()->push_constant(Value::make_bool(!value))); + + m_pc++; + } break; + case OPCODE_MK_FUNCTION: { auto code = program()->constant(pop()); diff --git a/meson.build b/meson.build index 7fa8c68..4da21c9 100644 --- a/meson.build +++ b/meson.build @@ -33,6 +33,7 @@ joko_lib = static_library( 'lib/Type.cpp', 'lib/Value.cpp', 'lib/Function.cpp', + 'lib/StaticFunction.cpp', 'lib/Code.cpp', 'lib/SymTable.cpp', 'lib/StaticPass.cpp', diff --git a/src/main.cpp b/src/main.cpp index f43093c..3bad465 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,12 +85,15 @@ int main(int argc, char** argv) auto compiler = std::make_shared(logger); + auto static_pass = std::make_shared(sym, logger); auto program = std::make_shared(); auto vm = std::make_shared(); - auto loader = std::make_shared(vm, sym); + + auto loader = std::make_shared(vm, static_pass, + compiler, sym); loader->load(); - auto static_pass = std::make_shared(sym, logger); + static_pass->pass(ast); compiler->compile(ast, program, sym);