diff --git a/src/logger/include/Logger.h b/src/logger/include/Logger.h index f52a55a..7b46e78 100644 --- a/src/logger/include/Logger.h +++ b/src/logger/include/Logger.h @@ -29,6 +29,8 @@ public: static void set_out(std::ostream &out); static void set_out_err(std::ostream &out_err); + static void reset(); + private: static Logger &get(); diff --git a/src/logger/src/Logger.cpp b/src/logger/src/Logger.cpp index 912155c..c38918b 100644 --- a/src/logger/src/Logger.cpp +++ b/src/logger/src/Logger.cpp @@ -44,3 +44,4 @@ void Logger::set_level(const std::string &tag, int level) { get()._levels[tag] = void Logger::set_out(std::ostream &out) { get()._out = out; } void Logger::set_out_err(std::ostream &out_err) { get()._out_err = out_err; } void Logger::set_default_level(int level) { get()._default_level = level; } +void Logger::reset() { get()._levels = {}; } diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index 0628937..7df94dd 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_library(vm src/VM.cpp src/Cell.cpp - src/Parser.cpp src/MemoryContext.cpp src/Handle.cpp src/Compiler.cpp) + src/Parser.cpp src/MemoryContext.cpp src/Handle.cpp src/Compiler.cpp src/Options.cpp) target_link_libraries(vm PUBLIC logger) diff --git a/src/vm/include/Command.h b/src/vm/include/Command.h index 1ce355f..27213af 100644 --- a/src/vm/include/Command.h +++ b/src/vm/include/Command.h @@ -8,6 +8,8 @@ #include #include "Cell.h" +#include "Handle.h" +#include "Options.h" namespace Command { enum Command : CellValType { @@ -40,9 +42,19 @@ namespace Command { }; static inline std::unordered_map str_to_cmd{ - {"NIL", 1}, {"LDC", 2}, {"LD", 3}, {"SEL", 4}, {"JOIN", 5}, {"LDF", 6}, {"AP", 7}, - {"RET", 8}, {"DUM", 9}, {"RAP", 10}, {"STOP", 11}, {"ATOM", 12}, {"ADD", 13}, {"SUB", 14}, - {"READCHAR", 15}, {"PUTCHAR", 16}, {"PUTNUM", 17}, {"EVAL", 18}, {"PRINT", 19}, {"READ", 20}, {"CONS", 21}, + {"NIL", 1}, {"LDC", 2}, {"LD", 3}, {"SEL", 4}, {"JOIN", 5}, {"LDF", 6}, {"AP", 7}, {"RET", 8}, + {"DUM", 9}, {"RAP", 10}, {"STOP", 11}, {"ATOM", 12}, {"ADD", 13}, {"SUB", 14}, {"READCHAR", 15}, {"PUTCHAR", 16}, + {"PUTNUM", 17}, {"EVAL", 18}, {"PRINT", 19}, {"READ", 20}, {"CONS", 21}, {"LDG", 22}}; + static inline std::unordered_map cmd_to_str{ + {1, "NIL"}, {2, "LDC"}, {3, "LD"}, {4, "SEL"}, {5, "JOIN"}, {6, "LDF"}, {7, "AP"}, {8, "RET"}, + {9, "DUM"}, {10, "RAP"}, {11, "STOP"}, {12, "ATOM"}, {13, "ADD"}, {14, "SUB"}, {15, "READCHAR"}, {16, "PUTCHAR"}, + {17, "PUTNUM"}, {18, "EVAL"}, {19, "PRINT"}, {20, "READ"}, {21, "CONS"}, {22, "LDG"}}; + + static inline Handle make_cmd(CellValType cmd) { + if (Options::get_bool("command_strs")) { + return Handle(cmd_to_str.at(cmd)); + } else + return Handle(cmd); }; };// namespace Command diff --git a/src/vm/include/MemoryContext.h b/src/vm/include/MemoryContext.h index 744cd1b..a6b6ecc 100644 --- a/src/vm/include/MemoryContext.h +++ b/src/vm/include/MemoryContext.h @@ -19,6 +19,7 @@ #include "Cell.h" #include "Handle.h" #include "Logger.h" +#include "Options.h" class Handle; @@ -72,17 +73,17 @@ private: tcellnum = _temp_cells.size(); } - if ((_cells_num + tcellnum) >= (_cell_limit)) { + if ((_cells_num + tcellnum) >= (Options::get_int("cell_limit"))) { // We might need to run GC twice as it has to process the messages; Logger::log("MemoryContext", "Running forced gc", Logger::ERROR); - for (int i = 0; i < 3 && (_cells_num + tcellnum) >= (_cell_limit); i++) { + for (int i = 0; i < 3 && (_cells_num + tcellnum) >= (Options::get_int("cell_limit")); i++) { request_gc_and_wait(); { std::lock_guard tmplg(_new_roots_lock); tcellnum = _temp_cells.size(); } } - if ((_cells_num + tcellnum) >= (_cell_limit)) { + if ((_cells_num + tcellnum) >= (Options::get_int("cell_limit"))) { Logger::log("MemoryContext", "Out of cells", Logger::ERROR); throw std::runtime_error("Out of cells"); @@ -95,7 +96,7 @@ private: std::lock_guard tmplg(_new_roots_lock); Handle ret(cell); _temp_cells.emplace_back(cell); - if ((_cells_num + _temp_cells.size() + 1) >= (size_t) (_cell_limit / 2)) { request_gc(); } + if ((_cells_num + _temp_cells.size() + 1) >= (size_t) (Options::get_int("cell_limit") / 2)) { request_gc(); } return ret; } } @@ -108,8 +109,6 @@ private: std::atomic _cells_num = 0; std::list _temp_cells; - static constexpr size_t _cell_limit = {50000}; - void gc_thread_entry(); std::map _roots; diff --git a/src/vm/include/Options.h b/src/vm/include/Options.h new file mode 100644 index 0000000..e431039 --- /dev/null +++ b/src/vm/include/Options.h @@ -0,0 +1,30 @@ +// +// Created by stepus53 on 3.1.24. +// + +#ifndef PSIL_OPTIONS_H +#define PSIL_OPTIONS_H + + +#include +#include +#include + +class Options { +public: + static bool get_bool(const std::string &opt); + static size_t get_int(const std::string &opt); + static void set_bool(const std::string &opt, bool val); + static void set_int(const std::string &opt, size_t val); + static void reset(); + +private: + const static inline std::unordered_map> _defaults{{"cell_limit", 50000U}, + {"command_strs", false}}; + + std::unordered_map> _current = _defaults; + static Options &get(); +}; + + +#endif//PSIL_OPTIONS_H diff --git a/src/vm/src/Compiler.cpp b/src/vm/src/Compiler.cpp index 9661f75..dac2e9d 100644 --- a/src/vm/src/Compiler.cpp +++ b/src/vm/src/Compiler.cpp @@ -25,10 +25,10 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi std::function compileArgsList = [&](Handle args, Handle env) { Handle out; - out.append(Handle(NIL)); + out.append(make_cmd(NIL)); while (!args.null()) { out.splice(compile(args.car(), env)); - out.append(Handle(CONS)); + out.append(make_cmd(CONS)); args = args.cdr(); } return out; @@ -37,18 +37,18 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi Handle expr = src; if (expr.null()) { - out.append(Handle(NIL)); + out.append(make_cmd(NIL)); } else if (expr.atom()) { if (expr.type() == CellType::NUMATOM) { - out.append(Handle(LDC)); + out.append(make_cmd(LDC)); out.append(expr); } else if (expr.type() == CellType::STRATOM) { Handle idx = findIndex(expr, fake_env); if (idx == nullptr) { - out.append(Handle(LDC)); + out.append(make_cmd(LDC)); out.append(expr); } else { - out.append(Handle(LD)); + out.append(make_cmd(LD)); out.append(idx); } } @@ -58,21 +58,21 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi if (car.atom()) { if (car.strval() == "+") { out.splice(compileArgsRaw(cdr)); - out.append(Handle(ADD)); + out.append(make_cmd(ADD)); } else if (car.strval() == "read") { - out.append(Handle(READ)); + out.append(make_cmd(READ)); } else if (car.strval() == "lambda") { - out.append(Handle(LDF)); - out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), Handle(RET))); + out.append(make_cmd(LDF)); + out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), make_cmd(RET))); } else if (car.strval() == "if") { out.splice(compile(cdr.car(), fake_env)); - out.append(Handle(SEL)); - out.append(compile(cdr.cdr().car(), fake_env, Handle(JOIN))); - out.append(compile(cdr.cdr().cdr().car(), fake_env, Handle(JOIN))); + out.append(make_cmd(SEL)); + out.append(compile(cdr.cdr().car(), fake_env, make_cmd(JOIN))); + out.append(compile(cdr.cdr().cdr().car(), fake_env, make_cmd(JOIN))); } else if (car.strval() == "define") { fake_env.car().append(Handle(std::string(cdr.car().car().strval()))); - out.append(Handle(LDG)); - out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car().cdr(), fake_env), Handle(RET))); + out.append(make_cmd(LDG)); + out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car().cdr(), fake_env), make_cmd(RET))); } else if (car.strval() == "let" || car.strval() == "letrec") { std::vector> argBody; @@ -93,27 +93,27 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi Handle newenv = Handle::cons(argNames, fake_env); if (car.strval() == "let") { out.splice(compileArgsList(argBodies, fake_env)); - out.append(Handle(LDF)); - out.append(compile(body, newenv, Handle(RET))); - out.append(Handle(AP)); + out.append(make_cmd(LDF)); + out.append(compile(body, newenv, make_cmd(RET))); + out.append(make_cmd(AP)); } else if (car.strval() == "letrec") { - out.append(Handle(DUM)); + out.append(make_cmd(DUM)); out.splice(compileArgsList(argBodies, newenv)); - out.append(Handle(LDF)); - out.append(compile(body, newenv, Handle(RET))); - out.append(Handle(RAP)); + out.append(make_cmd(LDF)); + out.append(compile(body, newenv, make_cmd(RET))); + out.append(make_cmd(RAP)); } } else { out.splice(compileArgsList(cdr, fake_env)); - out.append(Handle(LD)); + out.append(make_cmd(LD)); Handle idx = findIndex(car, fake_env); out.append(idx); - out.append(Handle(AP)); + out.append(make_cmd(AP)); } } else { out.splice(compileArgsList(cdr, fake_env)); - out.splice(compile(car, fake_env, Handle(AP))); + out.splice(compile(car, fake_env, make_cmd(AP))); } } out.splice(suffix); diff --git a/src/vm/src/Options.cpp b/src/vm/src/Options.cpp new file mode 100644 index 0000000..56f50fb --- /dev/null +++ b/src/vm/src/Options.cpp @@ -0,0 +1,37 @@ +// +// Created by stepus53 on 3.1.24. +// + +#include "Options.h" + +#include + +Options &Options::get() { + static Options opts; + return opts; +} +bool Options::get_bool(const std::string &opt) { + Options &o = get(); + if (_defaults.find(opt) == _defaults.end()) throw std::invalid_argument("Unknown option " + opt); + if (!std::holds_alternative(_defaults.at(opt))) throw std::invalid_argument("Bad option type " + opt); + return std::get(o._current.at(opt)); +} +size_t Options::get_int(const std::string &opt) { + Options &o = get(); + if (_defaults.find(opt) == _defaults.end()) throw std::invalid_argument("Unknown option " + opt); + if (!std::holds_alternative(_defaults.at(opt))) throw std::invalid_argument("Bad option type " + opt); + return std::get(o._current.at(opt)); +} +void Options::set_bool(const std::string &opt, bool val) { + Options &o = get(); + if (_defaults.find(opt) == _defaults.end()) throw std::invalid_argument("Unknown option " + opt); + if (!std::holds_alternative(_defaults.at(opt))) throw std::invalid_argument("Bad option type " + opt); + o._current[opt] = val; +} +void Options::set_int(const std::string &opt, size_t val) { + Options &o = get(); + if (_defaults.find(opt) == _defaults.end()) throw std::invalid_argument("Unknown option " + opt); + if (!std::holds_alternative(_defaults.at(opt))) throw std::invalid_argument("Bad option type " + opt); + o._current[opt] = val; +} +void Options::reset() { get()._current = _defaults; } diff --git a/test/vm/CompilerTest.cpp b/test/vm/CompilerTest.cpp index e97767a..6bc780c 100644 --- a/test/vm/CompilerTest.cpp +++ b/test/vm/CompilerTest.cpp @@ -4,9 +4,27 @@ #include #include "MemoryContext.h" +#include "Options.h" #include "Parser.h" #include "VM.h" +class Environment : public ::testing::Environment { +public: + ~Environment() override {} + + void SetUp() override { + Options::set_bool("command_strs", true); + Logger::set_level("Compiler", Logger::DEBUG); + } + + void TearDown() override { + Options::reset(); + Logger::reset(); + } +}; + +testing::Environment *const env = testing::AddGlobalTestEnvironment(new Environment); + TEST(CompilerTest, BasicHello) { std::stringstream ssin; std::stringstream ssout; @@ -146,7 +164,6 @@ TEST(CompilerTest, GlobalDefineFnRec) { std::stringstream ssin; std::stringstream ssout; { - VM vm(ssin, ssout); Parser parser; parser.loadStr(