This commit is contained in:
2024-01-03 17:03:06 +01:00
parent eeb6ca5f34
commit ddf7eeed4e
9 changed files with 134 additions and 36 deletions

View File

@@ -29,6 +29,8 @@ public:
static void set_out(std::ostream &out); static void set_out(std::ostream &out);
static void set_out_err(std::ostream &out_err); static void set_out_err(std::ostream &out_err);
static void reset();
private: private:
static Logger &get(); static Logger &get();

View File

@@ -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(std::ostream &out) { get()._out = out; }
void Logger::set_out_err(std::ostream &out_err) { get()._out_err = out_err; } 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::set_default_level(int level) { get()._default_level = level; }
void Logger::reset() { get()._levels = {}; }

View File

@@ -2,7 +2,7 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(vm src/VM.cpp src/Cell.cpp 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) target_link_libraries(vm PUBLIC logger)

View File

@@ -8,6 +8,8 @@
#include <unordered_map> #include <unordered_map>
#include "Cell.h" #include "Cell.h"
#include "Handle.h"
#include "Options.h"
namespace Command { namespace Command {
enum Command : CellValType { enum Command : CellValType {
@@ -40,9 +42,19 @@ namespace Command {
}; };
static inline std::unordered_map<std::string_view, CellValType> str_to_cmd{ static inline std::unordered_map<std::string_view, CellValType> str_to_cmd{
{"NIL", 1}, {"LDC", 2}, {"LD", 3}, {"SEL", 4}, {"JOIN", 5}, {"LDF", 6}, {"AP", 7}, {"NIL", 1}, {"LDC", 2}, {"LD", 3}, {"SEL", 4}, {"JOIN", 5}, {"LDF", 6}, {"AP", 7}, {"RET", 8},
{"RET", 8}, {"DUM", 9}, {"RAP", 10}, {"STOP", 11}, {"ATOM", 12}, {"ADD", 13}, {"SUB", 14}, {"DUM", 9}, {"RAP", 10}, {"STOP", 11}, {"ATOM", 12}, {"ADD", 13}, {"SUB", 14}, {"READCHAR", 15}, {"PUTCHAR", 16},
{"READCHAR", 15}, {"PUTCHAR", 16}, {"PUTNUM", 17}, {"EVAL", 18}, {"PRINT", 19}, {"READ", 20}, {"CONS", 21}, {"PUTNUM", 17}, {"EVAL", 18}, {"PRINT", 19}, {"READ", 20}, {"CONS", 21}, {"LDG", 22}};
static inline std::unordered_map<CellValType, std::string> 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 };// namespace Command

View File

@@ -19,6 +19,7 @@
#include "Cell.h" #include "Cell.h"
#include "Handle.h" #include "Handle.h"
#include "Logger.h" #include "Logger.h"
#include "Options.h"
class Handle; class Handle;
@@ -72,17 +73,17 @@ private:
tcellnum = _temp_cells.size(); 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; // We might need to run GC twice as it has to process the messages;
Logger::log("MemoryContext", "Running forced gc", Logger::ERROR); 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(); request_gc_and_wait();
{ {
std::lock_guard tmplg(_new_roots_lock); std::lock_guard tmplg(_new_roots_lock);
tcellnum = _temp_cells.size(); 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); Logger::log("MemoryContext", "Out of cells", Logger::ERROR);
throw std::runtime_error("Out of cells"); throw std::runtime_error("Out of cells");
@@ -95,7 +96,7 @@ private:
std::lock_guard tmplg(_new_roots_lock); std::lock_guard tmplg(_new_roots_lock);
Handle ret(cell); Handle ret(cell);
_temp_cells.emplace_back(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; return ret;
} }
} }
@@ -108,8 +109,6 @@ private:
std::atomic<size_t> _cells_num = 0; std::atomic<size_t> _cells_num = 0;
std::list<Cell *> _temp_cells; std::list<Cell *> _temp_cells;
static constexpr size_t _cell_limit = {50000};
void gc_thread_entry(); void gc_thread_entry();
std::map<Cell *, int64_t> _roots; std::map<Cell *, int64_t> _roots;

30
src/vm/include/Options.h Normal file
View File

@@ -0,0 +1,30 @@
//
// Created by stepus53 on 3.1.24.
//
#ifndef PSIL_OPTIONS_H
#define PSIL_OPTIONS_H
#include <string>
#include <unordered_map>
#include <variant>
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<std::string, std::variant<size_t, bool>> _defaults{{"cell_limit", 50000U},
{"command_strs", false}};
std::unordered_map<std::string, std::variant<size_t, bool>> _current = _defaults;
static Options &get();
};
#endif//PSIL_OPTIONS_H

View File

@@ -25,10 +25,10 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi
std::function<Handle(Handle, Handle)> compileArgsList = [&](Handle args, Handle env) { std::function<Handle(Handle, Handle)> compileArgsList = [&](Handle args, Handle env) {
Handle out; Handle out;
out.append(Handle(NIL)); out.append(make_cmd(NIL));
while (!args.null()) { while (!args.null()) {
out.splice(compile(args.car(), env)); out.splice(compile(args.car(), env));
out.append(Handle(CONS)); out.append(make_cmd(CONS));
args = args.cdr(); args = args.cdr();
} }
return out; return out;
@@ -37,18 +37,18 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi
Handle expr = src; Handle expr = src;
if (expr.null()) { if (expr.null()) {
out.append(Handle(NIL)); out.append(make_cmd(NIL));
} else if (expr.atom()) { } else if (expr.atom()) {
if (expr.type() == CellType::NUMATOM) { if (expr.type() == CellType::NUMATOM) {
out.append(Handle(LDC)); out.append(make_cmd(LDC));
out.append(expr); out.append(expr);
} else if (expr.type() == CellType::STRATOM) { } else if (expr.type() == CellType::STRATOM) {
Handle idx = findIndex(expr, fake_env); Handle idx = findIndex(expr, fake_env);
if (idx == nullptr) { if (idx == nullptr) {
out.append(Handle(LDC)); out.append(make_cmd(LDC));
out.append(expr); out.append(expr);
} else { } else {
out.append(Handle(LD)); out.append(make_cmd(LD));
out.append(idx); out.append(idx);
} }
} }
@@ -58,21 +58,21 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi
if (car.atom()) { if (car.atom()) {
if (car.strval() == "+") { if (car.strval() == "+") {
out.splice(compileArgsRaw(cdr)); out.splice(compileArgsRaw(cdr));
out.append(Handle(ADD)); out.append(make_cmd(ADD));
} else if (car.strval() == "read") { } else if (car.strval() == "read") {
out.append(Handle(READ)); out.append(make_cmd(READ));
} else if (car.strval() == "lambda") { } else if (car.strval() == "lambda") {
out.append(Handle(LDF)); out.append(make_cmd(LDF));
out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), Handle(RET))); out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), make_cmd(RET)));
} else if (car.strval() == "if") { } else if (car.strval() == "if") {
out.splice(compile(cdr.car(), fake_env)); out.splice(compile(cdr.car(), fake_env));
out.append(Handle(SEL)); out.append(make_cmd(SEL));
out.append(compile(cdr.cdr().car(), fake_env, Handle(JOIN))); out.append(compile(cdr.cdr().car(), fake_env, make_cmd(JOIN)));
out.append(compile(cdr.cdr().cdr().car(), fake_env, Handle(JOIN))); out.append(compile(cdr.cdr().cdr().car(), fake_env, make_cmd(JOIN)));
} else if (car.strval() == "define") { } else if (car.strval() == "define") {
fake_env.car().append(Handle(std::string(cdr.car().car().strval()))); fake_env.car().append(Handle(std::string(cdr.car().car().strval())));
out.append(Handle(LDG)); out.append(make_cmd(LDG));
out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car().cdr(), fake_env), Handle(RET))); out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car().cdr(), fake_env), make_cmd(RET)));
} else if (car.strval() == "let" || car.strval() == "letrec") { } else if (car.strval() == "let" || car.strval() == "letrec") {
std::vector<std::pair<Handle, Handle>> argBody; std::vector<std::pair<Handle, Handle>> argBody;
@@ -93,27 +93,27 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi
Handle newenv = Handle::cons(argNames, fake_env); Handle newenv = Handle::cons(argNames, fake_env);
if (car.strval() == "let") { if (car.strval() == "let") {
out.splice(compileArgsList(argBodies, fake_env)); out.splice(compileArgsList(argBodies, fake_env));
out.append(Handle(LDF)); out.append(make_cmd(LDF));
out.append(compile(body, newenv, Handle(RET))); out.append(compile(body, newenv, make_cmd(RET)));
out.append(Handle(AP)); out.append(make_cmd(AP));
} else if (car.strval() == "letrec") { } else if (car.strval() == "letrec") {
out.append(Handle(DUM)); out.append(make_cmd(DUM));
out.splice(compileArgsList(argBodies, newenv)); out.splice(compileArgsList(argBodies, newenv));
out.append(Handle(LDF)); out.append(make_cmd(LDF));
out.append(compile(body, newenv, Handle(RET))); out.append(compile(body, newenv, make_cmd(RET)));
out.append(Handle(RAP)); out.append(make_cmd(RAP));
} }
} else { } else {
out.splice(compileArgsList(cdr, fake_env)); out.splice(compileArgsList(cdr, fake_env));
out.append(Handle(LD)); out.append(make_cmd(LD));
Handle idx = findIndex(car, fake_env); Handle idx = findIndex(car, fake_env);
out.append(idx); out.append(idx);
out.append(Handle(AP)); out.append(make_cmd(AP));
} }
} else { } else {
out.splice(compileArgsList(cdr, fake_env)); 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); out.splice(suffix);

37
src/vm/src/Options.cpp Normal file
View File

@@ -0,0 +1,37 @@
//
// Created by stepus53 on 3.1.24.
//
#include "Options.h"
#include <stdexcept>
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<bool>(_defaults.at(opt))) throw std::invalid_argument("Bad option type " + opt);
return std::get<bool>(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<size_t>(_defaults.at(opt))) throw std::invalid_argument("Bad option type " + opt);
return std::get<size_t>(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<bool>(_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<size_t>(_defaults.at(opt))) throw std::invalid_argument("Bad option type " + opt);
o._current[opt] = val;
}
void Options::reset() { get()._current = _defaults; }

View File

@@ -4,9 +4,27 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "MemoryContext.h" #include "MemoryContext.h"
#include "Options.h"
#include "Parser.h" #include "Parser.h"
#include "VM.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) { TEST(CompilerTest, BasicHello) {
std::stringstream ssin; std::stringstream ssin;
std::stringstream ssout; std::stringstream ssout;
@@ -146,7 +164,6 @@ TEST(CompilerTest, GlobalDefineFnRec) {
std::stringstream ssin; std::stringstream ssin;
std::stringstream ssout; std::stringstream ssout;
{ {
VM vm(ssin, ssout); VM vm(ssin, ssout);
Parser parser; Parser parser;
parser.loadStr( parser.loadStr(