From 4a02d7f231f9db9f1a5b5b79418bbb0bb364f446 Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Fri, 29 Dec 2023 00:38:20 +0100 Subject: [PATCH] compiler! --- src/vm/CMakeLists.txt | 2 +- src/vm/includes/Cell.h | 38 ++++++++- src/vm/includes/Compiler.h | 19 +++++ src/vm/includes/Handle.h | 39 +++++++++- src/vm/includes/MemoryContext.h | 57 ++------------ src/vm/includes/VM.h | 4 + src/vm/src/Compiler.cpp | 132 ++++++++++++++++++++++++++++++++ src/vm/src/Handle.cpp | 19 ++++- src/vm/src/MemoryContext.cpp | 131 ++++++++++++++++++++++--------- src/vm/src/Parser.cpp | 6 +- src/vm/src/VM.cpp | 14 ++++ test/vm/CMakeLists.txt | 12 +++ test/vm/CompilerTest.cpp | 96 +++++++++++++++++++++++ test/vm/GCTest.cpp | 3 +- 14 files changed, 475 insertions(+), 97 deletions(-) create mode 100644 src/vm/includes/Compiler.h create mode 100644 src/vm/src/Compiler.cpp create mode 100644 test/vm/CompilerTest.cpp diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index 02bc022..cfb706f 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -2,6 +2,6 @@ set(CMAKE_CXX_STANDARD 20) 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/Parser.cpp src/MemoryContext.cpp src/Handle.cpp src/Compiler.cpp) target_include_directories(vm PUBLIC includes) diff --git a/src/vm/includes/Cell.h b/src/vm/includes/Cell.h index d869096..d3baa57 100644 --- a/src/vm/includes/Cell.h +++ b/src/vm/includes/Cell.h @@ -7,9 +7,10 @@ #include #include +#include +#include #include #include - enum class CellType { NUMATOM, STRATOM, @@ -23,7 +24,9 @@ struct Cell { virtual ~Cell() = 0; CellType _type; - std::atomic live = false; + std::atomic _live = false; + + virtual void print(std::ostream &out) = 0; }; struct NumAtomCell : public Cell { @@ -31,6 +34,10 @@ struct NumAtomCell : public Cell { explicit NumAtomCell(CellValType val) : Cell(CellType::NUMATOM), _val(val) {} CellValType _val; + + void print(std::ostream &out) override { + out << _val; + } }; struct StrAtomCell : public Cell { @@ -38,6 +45,10 @@ struct StrAtomCell : public Cell { explicit StrAtomCell(std::string val) : Cell(CellType::STRATOM), _val(std::move(val)) {} std::string _val; + + void print(std::ostream &out) override { + out << _val; + } }; struct ConsCell : public Cell { @@ -47,6 +58,29 @@ struct ConsCell : public Cell { std::atomic _car = nullptr; std::atomic _cdr = nullptr; + + void print(std::ostream &out) override { + std::stringstream res; + if (_car) { + if (_car.load()->_type == CellType::CONS) { + res << "("; + _car.load()->print(res); + res << ")"; + } else { + _car.load()->print(res); + } + } + if (_cdr) { + if (_cdr.load()->_type == CellType::CONS) { + res << " "; + _cdr.load()->print(res); + } else { + res << "."; + _cdr.load()->print(res); + } + } + out << res.str(); + } }; #endif//PSIL_CELL_H diff --git a/src/vm/includes/Compiler.h b/src/vm/includes/Compiler.h new file mode 100644 index 0000000..e071850 --- /dev/null +++ b/src/vm/includes/Compiler.h @@ -0,0 +1,19 @@ +// +// Created by Stepan Usatiuk on 27.12.2023. +// + +#ifndef PSIL_COMPILER_H +#define PSIL_COMPILER_H + + +#include "Handle.h" +class Compiler { +public: + static Handle compile(Handle src, Handle fake_env = nullptr, Handle suffix = nullptr); + +private: + static Handle findIndex(Handle symbol, Handle env); +}; + + +#endif//PSIL_COMPILER_H diff --git a/src/vm/includes/Handle.h b/src/vm/includes/Handle.h index 27eee3b..2504850 100644 --- a/src/vm/includes/Handle.h +++ b/src/vm/includes/Handle.h @@ -13,7 +13,7 @@ class Handle { public: friend MemoryContext; - Handle(Cell *target); + Handle(Cell *target = nullptr); Handle(int64_t val); Handle(std::string strval); ~Handle(); @@ -22,7 +22,20 @@ public: Handle &operator=(Handle other); bool operator==(const Handle &rhs) const { - return _target == rhs._target; + if (_target == rhs._target) { + return true; + } else if ((_target != nullptr && rhs._target != nullptr) && (_target->_type == rhs._target->_type)) { + if (_target->_type == CellType::NUMATOM) { + return dynamic_cast(*_target)._val == dynamic_cast(*rhs._target)._val; + } else if (_target->_type == CellType::STRATOM) { + return dynamic_cast(*_target)._val == dynamic_cast(*rhs._target)._val; + } else if (_target->_type == CellType::CONS) { + // This is questionable + return dynamic_cast(*_target)._car == dynamic_cast(*rhs._target)._car && + dynamic_cast(*_target)._cdr == dynamic_cast(*rhs._target)._cdr; + } + } + return false; } static Handle cons(const Handle &car, const Handle &cdr); @@ -32,15 +45,37 @@ public: CellValType val() { return dynamic_cast(*_target)._val; } std::string_view strval() { return dynamic_cast(*_target)._val; } + CellType type() const { + if (!_target) return CellType::CONS; + return _target->_type; + } + + bool atom() const { + return type() != CellType::CONS; + } + + bool null() { + if (!_target) return true; + if (type() == CellType::CONS && car() == nullptr && cdr() == nullptr) return true; + return false; + } + Handle pop(); void push(const Handle &what); void append(const Handle &what); + void splice(const Handle &what); static Handle makeNumCell(int64_t val); static Handle makeStrCell(std::string val); void setcar(const Handle &car); void setcdr(const Handle &cdr); + friend std::ostream &operator<<(std::ostream &stream, const Handle &h) { + if (h._target) + h._target->print(stream); + return stream; + } + private: Cell *operator->() const { return _target; } Cell &operator*() const { return *_target; } diff --git a/src/vm/includes/MemoryContext.h b/src/vm/includes/MemoryContext.h index 72369ec..393b94e 100644 --- a/src/vm/includes/MemoryContext.h +++ b/src/vm/includes/MemoryContext.h @@ -32,50 +32,6 @@ public: return alloc_cell(std::forward(args)...); } - template<> - Handle create_cell(CellValType val) { - std::optional ret = run_dirty>([&](std::function dirty) -> std::optional { - std::lock_guard il(_indexes_lock); - if (_numatom_index.contains(val)) { - dirty(_numatom_index.at(val)); - return _numatom_index.at(val); - } else { - return std::nullopt; - } - }); - - if (ret.has_value()) return *ret; - - Handle newc = alloc_cell(val); - { - std::lock_guard il(_indexes_lock); - _numatom_index.emplace(val, newc.get()); - } - return newc; - } - - template<> - Handle create_cell(std::string val) { - std::optional ret = run_dirty>([&](std::function dirty) -> std::optional { - std::lock_guard il(_indexes_lock); - if (_stratom_index.contains(val)) { - dirty(_stratom_index.at(val)); - return _stratom_index.at(val); - } else { - return std::nullopt; - } - }); - - if (ret.has_value()) return *ret; - - Handle newc = alloc_cell(val); - { - std::lock_guard il(_indexes_lock); - _stratom_index.emplace(val, newc.get()); - } - return newc; - } - void request_gc_and_wait() { std::unique_lock l(_gc_done_m); @@ -100,7 +56,14 @@ public: template R run_dirty(const std::function)> &f) { std::lock_guard l(_gc_dirty_notif_queue_lock); - return f([&](Cell *c) { _gc_dirty_notif_queue.emplace(c); }); + return f([&](Cell *c) { +// { +// std::stringstream out; +// out << "marked dirty: " << c << " \n"; +// std::cerr << out.str(); +// } + + _gc_dirty_notif_queue.emplace(c); }); } private: @@ -149,10 +112,6 @@ private: std::atomic _cells_num = 0; std::list _temp_cells; - std::mutex _indexes_lock; - std::unordered_map _numatom_index; - std::unordered_map _stratom_index; - static constexpr size_t _cell_limit = {50000}; void gc_thread_entry(); diff --git a/src/vm/includes/VM.h b/src/vm/includes/VM.h index 67147d1..4ecbe94 100644 --- a/src/vm/includes/VM.h +++ b/src/vm/includes/VM.h @@ -45,6 +45,7 @@ private: Handle RAP = Handle::makeStrCell("RAP"); Handle STOP = Handle::makeStrCell("STOP"); + Handle ATOM = Handle::makeStrCell("ATOM"); Handle ADD = Handle::makeStrCell("ADD"); Handle SUB = Handle::makeStrCell("SUB"); @@ -52,6 +53,9 @@ private: Handle PUTCHAR = Handle::makeStrCell("PUTCHAR"); Handle PUTNUM = Handle::makeStrCell("PUTNUM"); + Handle EVAL = Handle::makeStrCell("EVAL"); + Handle PRINT = Handle::makeStrCell("PRINT"); + Handle CONS = Handle::makeStrCell("CONS"); }; diff --git a/src/vm/src/Compiler.cpp b/src/vm/src/Compiler.cpp new file mode 100644 index 0000000..be29a30 --- /dev/null +++ b/src/vm/src/Compiler.cpp @@ -0,0 +1,132 @@ +// +// Created by Stepan Usatiuk on 27.12.2023. +// + +#include "Compiler.h" + +#include + +Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { + Handle out; + + std::function compileArgsRaw = [&](Handle args) { + Handle out; + while (args != nullptr) { + out.splice(compile(args.car(), fake_env)); + args = args.cdr(); + } + return out; + }; + + std::function compileArgsList = [&](Handle args, Handle env) { + Handle out; + out.append(Handle("NIL")); + while (args != nullptr) { + out.splice(compile(args.car(), env)); + out.append(Handle("CONS")); + args = args.cdr(); + } + return out; + }; + + + Handle expr = src; + if (expr.null()) { + out.append(Handle("NIL")); + } else if (expr.atom()) { + if (expr.type() == CellType::NUMATOM) { + out.append(Handle("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(expr); + } else { + out.append(Handle("LD")); + out.append(idx); + } + } + } else { + Handle car = expr.car(); + Handle cdr = expr.cdr(); + if (car.atom()) { + if (car.strval() == "+") { + out.splice(compileArgsRaw(cdr)); + out.append(Handle("ADD")); + } else if (car.strval() == "lambda") { + out.append(Handle("LDF")); + out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), Handle("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"))); + } else if (car.strval() == "let" || car.strval() == "letrec") { + std::vector> argBody; + + Handle definitions = cdr.car(); + + Handle argNames; + Handle argBodies; + + Handle body = cdr.cdr().car(); + + while (definitions != nullptr) { + argBody.emplace_back(definitions.car().car(), definitions.car().cdr().car()); + argNames.append(definitions.car().car()); + argBodies.append(definitions.car().cdr().car()); + definitions = definitions.cdr(); + } + + Handle newenv = Handle::cons(argNames, fake_env); + if (car.strval() == "let") + out.splice(compileArgsList(argBodies, fake_env)); + else if (car.strval() == "letrec") { + out.append(Handle("DUM")); + out.splice(compileArgsList(argBodies, newenv)); + } + + out.append(Handle("LDF")); + out.append(compile(body, newenv, Handle("RET"))); + if (car.strval() == "let") + out.append(Handle("AP")); + else + out.append(Handle("RAP")); + } else { + out.splice(compileArgsList(cdr, fake_env)); + + out.append(Handle("LD")); + Handle idx = findIndex(car, fake_env); + out.append(idx); + out.append(Handle("AP")); + } + } else { + out.splice(compileArgsList(cdr, fake_env)); + out.splice(compile(car, fake_env, Handle("AP"))); + } + } + out.splice(suffix); + return out; +} +Handle Compiler::findIndex(Handle symbol, Handle env) { + int64_t frame = 1; + + Handle curFrame = env; + + while (curFrame != nullptr) { + int64_t arg = 1; + Handle curArg = curFrame.car(); + + while (curArg != nullptr) { + if (curArg.car() == symbol) return Handle::cons(frame, arg); + curArg = curArg.cdr(); + arg++; + } + + curFrame = curFrame.cdr(); + frame++; + } + + return Handle(nullptr); +} diff --git a/src/vm/src/Handle.cpp b/src/vm/src/Handle.cpp index 71b03be..c1eb872 100644 --- a/src/vm/src/Handle.cpp +++ b/src/vm/src/Handle.cpp @@ -42,8 +42,8 @@ void Handle::push(const Handle &what) { } void Handle::append(const Handle &what) { + if (_target == nullptr) *this = cons(nullptr, nullptr); Handle cur = *this; - assert(cur.get() != nullptr); if (cur.car().get() == nullptr) { cur.setcar(what); return; @@ -52,6 +52,23 @@ void Handle::append(const Handle &what) { cur.setcdr(cons(what, nullptr)); } +void Handle::splice(const Handle &what) { + if (_target == nullptr) { + *this = what; + return; + } + Handle cur = *this; + if (cur.car().get() == nullptr) { + *this = what; + return; + } + while (cur.cdr().get() != nullptr) + cur = cur.cdr(); + if (what.atom()) cur.setcdr(Handle::cons(what, nullptr)); + else + cur.setcdr(what); +} + Handle Handle::makeNumCell(int64_t val) { return CURRENT_MC.load()->create_cell(val); } diff --git a/src/vm/src/MemoryContext.cpp b/src/vm/src/MemoryContext.cpp index 7183710..01753a7 100644 --- a/src/vm/src/MemoryContext.cpp +++ b/src/vm/src/MemoryContext.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include std::atomic CURRENT_MC = nullptr; @@ -34,14 +35,22 @@ void MemoryContext::add_root(Cell *c) { { std::lock_guard l(_new_roots_lock); _new_roots[c]++; - // std::cerr << "new root: " << c << " T: " << static_cast(c->_type) << " NUM: " << _new_roots[c] << "\n"; + // { + // std::stringstream out; + // out << "new root: " << c << " T: " << static_cast(c->_type) << " NUM: " << _new_roots[c] << "\n"; + // std::cerr << out.str(); + // } } } void MemoryContext::remove_root(Cell *c) { { std::lock_guard l(_new_roots_lock); _new_roots[c]--; - // std::cerr << "del root: " << c << " T: " << static_cast(c->_type) << " NUM: " << _new_roots[c] << "\n"; + // { + // std::stringstream out; + // out << "del root: " << c << " T: " << static_cast(c->_type) << " NUM: " << _new_roots[c] << "\n"; + // std::cerr << out.str(); + // } if (_new_roots[c] == 0) _new_roots.erase(c); } } @@ -54,7 +63,11 @@ void MemoryContext::gc_thread_entry() { } if (_gc_thread_stop) return; - std::cerr << "gc start " << '\n'; + // { + // std::stringstream out; + // out << "gc start " << '\n'; + // std::cerr << out.str(); + // } auto gcstart = std::chrono::high_resolution_clock::now(); std::queue toVisit; @@ -65,19 +78,23 @@ void MemoryContext::gc_thread_entry() { toVisit.pop(); if (c == nullptr) continue; - if (c->live) continue; - c->live = true; - - // std::cerr << "processing c " << c << " " << static_cast(c->_type) << "\n"; + if (c->_live) continue; + c->_live = true; + // + // { + // std::stringstream out; + // out << "processing c " << c << " " << static_cast(c->_type) << "\n"; + // std::cerr << out.str(); + // } if (c->_type == CellType::CONS) { ConsCell &cc = dynamic_cast(*c); - // std::cerr << "processing car " << cc._car << "\n"; + // {std::stringstream out; out << "processing car " << cc._car << "\n"; std::cerr<(stop - start).count() << "\n"; + { + std::stringstream out; + out << "New roots time: " << std::chrono::duration_cast(stop - start).count() << "\n"; + std::cout << out.str(); + } } { auto start = std::chrono::high_resolution_clock::now(); std::for_each(_cells.begin(), _cells.end(), [&](Cell *c) { - c->live = false; + c->_live = false; }); for (const auto &r: _roots) { - // std::cerr << "processing r " << r.first << " diff " << r.second << "\n"; + // { + // std::stringstream out; + // out << "processing r " << r.first << " diff " << r.second << "\n"; + // std::cerr << out.str(); + // } toVisit.emplace(r.first); } visitAll(); auto stop = std::chrono::high_resolution_clock::now(); - // std::cerr << "Scanned " << _roots.size() << " roots" << std::endl; - std::cerr << "Roots scan time: " << std::chrono::duration_cast(stop - start).count() << "\n"; + // { + // std::stringstream out; + // out << "Scanned " << _roots.size() << " roots" << std::endl; + // std::cerr << out.str(); + // } + { + std::stringstream out; + out << "Roots scan time: " << std::chrono::duration_cast(stop - start).count() << "\n"; + std::cout << out.str(); + } } { auto start = std::chrono::high_resolution_clock::now(); decltype(_gc_dirty_notif_queue) dirtied; - std::unique_lock dql(_gc_dirty_notif_queue_lock); - std::swap(dirtied, _gc_dirty_notif_queue); - + { + std::lock_guard dql(_gc_dirty_notif_queue_lock); + std::swap(dirtied, _gc_dirty_notif_queue); + } while (!dirtied.empty()) { - dql.unlock(); for (const auto &r: dirtied) { - // std::cerr << "processing dirty " << r << "\n"; + // { + // std::stringstream out; + // out << "processing dirty " << r << "\n"; + // std::cerr << out.str(); + // } toVisit.emplace(r); } visitAll(); dirtied = {}; - dql.lock(); - std::swap(dirtied, _gc_dirty_notif_queue); + { + std::lock_guard dql(_gc_dirty_notif_queue_lock); + std::swap(dirtied, _gc_dirty_notif_queue); + } } auto stop = std::chrono::high_resolution_clock::now(); - std::cerr << "Dirty mark time: " << std::chrono::duration_cast(stop - start).count() << "\n"; + { + std::stringstream out; + out << "Dirty mark time: " << std::chrono::duration_cast(stop - start).count() << "\n"; + std::cout << out.str(); + } } { auto start = std::chrono::high_resolution_clock::now(); @@ -152,18 +199,14 @@ void MemoryContext::gc_thread_entry() { uint64_t freed = 0; _cells.remove_if([&](Cell *l) { - if (!l->live) { + if (!l->_live) { freed += 1; - if (l->_type == CellType::NUMATOM) { - std::lock_guard il(_indexes_lock); - // std::cerr << "deleting num: " << l << "\n"; - _numatom_index.erase(dynamic_cast(*l)._val); - } else if (l->_type == CellType::STRATOM) { - std::lock_guard il(_indexes_lock); - // std::cerr << "deleting str: " << l << "\n"; - _stratom_index.erase(dynamic_cast(*l)._val); - } + // { + // std::stringstream out; + // out << "deleting: " << l << "\n"; + // std::cerr << out.str(); + // } delete l; return true; @@ -172,13 +215,25 @@ void MemoryContext::gc_thread_entry() { }); auto stop = std::chrono::high_resolution_clock::now(); - std::cerr << "Sweep time: " << std::chrono::duration_cast(stop - start).count() << "\n"; + { + std::stringstream out; + out << "Sweep time: " << std::chrono::duration_cast(stop - start).count() << "\n"; + std::cout << out.str(); + } _cells_num = _cells.size(); - std::cerr << "GC Freed " << freed << " cells left: " << _cells_num << " \n"; + { + std::stringstream out; + out << "GC Freed " << freed << " cells left: " << _cells_num << " \n"; + std::cout << out.str(); + } } auto gcstop = std::chrono::high_resolution_clock::now(); - std::cerr << "GC total time: " << std::chrono::duration_cast(gcstop - gcstart).count() << "\n"; + { + std::stringstream out; + out << "GC total time: " << std::chrono::duration_cast(gcstop - gcstart).count() << "\n"; + std::cout << out.str(); + } { diff --git a/src/vm/src/Parser.cpp b/src/vm/src/Parser.cpp index fb6bbb9..9335cb2 100644 --- a/src/vm/src/Parser.cpp +++ b/src/vm/src/Parser.cpp @@ -39,10 +39,10 @@ Handle Parser::parseExpr() { return out; } else { token = _tokenizer.getNext(); - try { + if (token.find_first_not_of("-0123456789") == std::string::npos) { CellValType val = std::stoi(token); return Handle::makeNumCell(val); - } catch (...) { + } else { return Handle::makeStrCell(token); } } @@ -63,7 +63,7 @@ std::string_view Parser::Tokenizer::peek() const { void Parser::Tokenizer::load(std::string_view input) { std::string_view::size_type curpos = input.find_first_not_of(' '); - static const std::string alnum = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + static const std::string alnum = "-+0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static const std::string special = "()."; while (curpos != std::string_view::npos) { diff --git a/src/vm/src/VM.cpp b/src/vm/src/VM.cpp index 25aadc8..291ecd4 100644 --- a/src/vm/src/VM.cpp +++ b/src/vm/src/VM.cpp @@ -6,6 +6,7 @@ #include #include +#include "Compiler.h" #include "VM.h" @@ -21,6 +22,8 @@ void VM::step() { _s.push(nullptr); } else if (poppedH == LDC) { _s.push(_c.pop()); + } else if (poppedH == ATOM) { + _s.push(_c.pop().atom() ? 1 : 0); } else if (poppedH == LD) { Handle poppedH2 = _c.pop(); @@ -123,6 +126,17 @@ void VM::step() { _outstream << (char) _s.pop().val(); } else if (poppedH == PUTNUM) { _outstream << _s.pop().val(); + } else if (poppedH == EVAL) { + Handle code = _s.pop(); + Handle newc = Compiler::compile(code, nullptr); + std::cerr << "compiled:\n"; + std::cerr << "(" << code << ")\n"; + std::cerr << "to:\n"; + std::cerr << "(" << newc << ")\n"; + newc.splice(_c); + _c = newc; + } else if (poppedH == PRINT) { + _outstream << _s.pop().val(); } else { assert(false); } diff --git a/test/vm/CMakeLists.txt b/test/vm/CMakeLists.txt index 1faa1b2..056e72d 100644 --- a/test/vm/CMakeLists.txt +++ b/test/vm/CMakeLists.txt @@ -28,7 +28,19 @@ target_link_libraries( GTest::gtest_main ) +add_executable( + CompilerTest + CompilerTest.cpp +) +target_link_libraries( + CompilerTest + vm + GTest::gtest_main +) + + include(GoogleTest) gtest_discover_tests(VMTest) gtest_discover_tests(VMWithParserTest) gtest_discover_tests(GCTest) +gtest_discover_tests(CompilerTest) diff --git a/test/vm/CompilerTest.cpp b/test/vm/CompilerTest.cpp new file mode 100644 index 0000000..f287379 --- /dev/null +++ b/test/vm/CompilerTest.cpp @@ -0,0 +1,96 @@ +// +// Created by Stepan Usatiuk on 27.12.2023. +// +#include + +#include "MemoryContext.h" +#include "Parser.h" +#include "VM.h" + +TEST(CompilerTest, BasicHello) { + std::stringstream ssin; + std::stringstream ssout; + { + MemoryContext mc; + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC 3 EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "3"); +} + +TEST(CompilerTest, BasicLet) { + std::stringstream ssin; + std::stringstream ssout; + { + MemoryContext mc; + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC (let ((x 1)) x) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "1"); +} + +TEST(CompilerTest, BasicFn) { + std::stringstream ssin; + std::stringstream ssout; + { + MemoryContext mc; + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC (let ((plfn (lambda (a b) (+ a b)))) (plfn 2 3)) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "5"); +} + +TEST(CompilerTest, BasicFnIfT) { + std::stringstream ssin; + std::stringstream ssout; + { + MemoryContext mc; + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC (let ((plfn (lambda (a) (if a 1 2)))) (plfn 1)) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "1"); +} +TEST(CompilerTest, BasicFnIfF) { + std::stringstream ssin; + std::stringstream ssout; + { + MemoryContext mc; + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC (let ((plfn (lambda (a) (if a 1 2)))) (plfn 0)) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "2"); +} +TEST(CompilerTest, RecursiveFn) { + std::stringstream ssin; + std::stringstream ssout; + { + MemoryContext mc; + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC (letrec ((fib (lambda (n) (if n (if (+ n -1) (+ (fib (+ n -1)) (fib(+ n -2))) 1) 0) ))) (fib 10)) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "55"); +} \ No newline at end of file diff --git a/test/vm/GCTest.cpp b/test/vm/GCTest.cpp index 5280bde..1b3cf1c 100644 --- a/test/vm/GCTest.cpp +++ b/test/vm/GCTest.cpp @@ -85,8 +85,9 @@ TEST(GCTest, GCTestAppend2) { TEST(GCTest, GCTestAppend3) { MemoryContext mc; - for (int i = 0; i < 25000; i++) { + for (int i = 0; i < 250000; i++) { Handle c = Handle::cons(nullptr, nullptr); + mc.request_gc(); c.append(Handle::makeNumCell(1)); c.append(Handle::makeNumCell(2)); mc.request_gc();