compiler!

This commit is contained in:
2023-12-29 00:38:20 +01:00
parent b3b1bbbaeb
commit 4a02d7f231
14 changed files with 475 additions and 97 deletions

View File

@@ -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)

View File

@@ -7,9 +7,10 @@
#include <cassert>
#include <cstdint>
#include <ostream>
#include <sstream>
#include <string>
#include <utility>
enum class CellType {
NUMATOM,
STRATOM,
@@ -23,7 +24,9 @@ struct Cell {
virtual ~Cell() = 0;
CellType _type;
std::atomic<bool> live = false;
std::atomic<bool> _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<Cell *> _car = nullptr;
std::atomic<Cell *> _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

View File

@@ -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

View File

@@ -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<NumAtomCell &>(*_target)._val == dynamic_cast<NumAtomCell &>(*rhs._target)._val;
} else if (_target->_type == CellType::STRATOM) {
return dynamic_cast<StrAtomCell &>(*_target)._val == dynamic_cast<StrAtomCell &>(*rhs._target)._val;
} else if (_target->_type == CellType::CONS) {
// This is questionable
return dynamic_cast<ConsCell &>(*_target)._car == dynamic_cast<ConsCell &>(*rhs._target)._car &&
dynamic_cast<ConsCell &>(*_target)._cdr == dynamic_cast<ConsCell &>(*rhs._target)._cdr;
}
}
return false;
}
static Handle cons(const Handle &car, const Handle &cdr);
@@ -32,15 +45,37 @@ public:
CellValType val() { return dynamic_cast<NumAtomCell &>(*_target)._val; }
std::string_view strval() { return dynamic_cast<StrAtomCell &>(*_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; }

View File

@@ -32,50 +32,6 @@ public:
return alloc_cell<CT>(std::forward<Args>(args)...);
}
template<>
Handle create_cell<NumAtomCell>(CellValType val) {
std::optional<Handle> ret = run_dirty<std::optional<Handle>>([&](std::function<void(Cell *)> dirty) -> std::optional<Handle> {
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<NumAtomCell>(val);
{
std::lock_guard il(_indexes_lock);
_numatom_index.emplace(val, newc.get());
}
return newc;
}
template<>
Handle create_cell<StrAtomCell>(std::string val) {
std::optional<Handle> ret = run_dirty<std::optional<Handle>>([&](std::function<void(Cell *)> dirty) -> std::optional<Handle> {
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<StrAtomCell>(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<typename R>
R run_dirty(const std::function<R(std::function<void(Cell *)>)> &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<size_t> _cells_num = 0;
std::list<Cell *> _temp_cells;
std::mutex _indexes_lock;
std::unordered_map<CellValType, Cell *> _numatom_index;
std::unordered_map<std::string, Cell *> _stratom_index;
static constexpr size_t _cell_limit = {50000};
void gc_thread_entry();

View File

@@ -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");
};

132
src/vm/src/Compiler.cpp Normal file
View File

@@ -0,0 +1,132 @@
//
// Created by Stepan Usatiuk on 27.12.2023.
//
#include "Compiler.h"
#include <string>
Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) {
Handle out;
std::function<Handle(Handle)> compileArgsRaw = [&](Handle args) {
Handle out;
while (args != nullptr) {
out.splice(compile(args.car(), fake_env));
args = args.cdr();
}
return out;
};
std::function<Handle(Handle, Handle)> 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<std::pair<Handle, Handle>> 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);
}

View File

@@ -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<NumAtomCell>(val);
}

View File

@@ -7,6 +7,7 @@
#include <chrono>
#include <exception>
#include <iostream>
#include <sstream>
#include <unordered_set>
std::atomic<MemoryContext *> 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<int>(c->_type) << " NUM: " << _new_roots[c] << "\n";
// {
// std::stringstream out;
// out << "new root: " << c << " T: " << static_cast<int>(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<int>(c->_type) << " NUM: " << _new_roots[c] << "\n";
// {
// std::stringstream out;
// out << "del root: " << c << " T: " << static_cast<int>(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<Cell *> 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<int>(c->_type) << "\n";
if (c->_live) continue;
c->_live = true;
//
// {
// std::stringstream out;
// out << "processing c " << c << " " << static_cast<int>(c->_type) << "\n";
// std::cerr << out.str();
// }
if (c->_type == CellType::CONS) {
ConsCell &cc = dynamic_cast<ConsCell &>(*c);
// std::cerr << "processing car " << cc._car << "\n";
// {std::stringstream out; out << "processing car " << cc._car << "\n"; std::cerr<<out.str();}
toVisit.emplace(cc._car);
// std::cerr << "real car " << toVisit.back() << "\n";
// std::cerr << "processing cdr " << cc._cdr << "\n";
// {std::stringstream out; out << "real car " << toVisit.back() << "\n"; std::cerr<<out.str();}
// {std::stringstream out; out << "processing cdr " << cc._cdr << "\n"; std::cerr<<out.str();}
toVisit.emplace(cc._cdr);
// std::cerr << "real cdr " << toVisit.back() << "\n";
// {std::stringstream out; out << "real cdr " << toVisit.back() << "\n"; std::cerr<<out.str();}
}
}
};
@@ -97,7 +114,11 @@ void MemoryContext::gc_thread_entry() {
for (auto const &r: new_roots) {
// std::cerr << "processing new " << r.first << " diff " << r.second << "\n";
// {
// std::stringstream out;
// out << "processing new " << r.first << " diff " << r.second << "\n";
// std::cerr << out.str();
// }
if (r.second == 0) continue;
_roots[r.first] += r.second;
if (_roots[r.first] <= 0)
@@ -105,46 +126,72 @@ void MemoryContext::gc_thread_entry() {
}
auto stop = std::chrono::high_resolution_clock::now();
std::cerr << "New roots time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
{
std::stringstream out;
out << "New roots time: " << std::chrono::duration_cast<std::chrono::microseconds>(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<std::chrono::microseconds>(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<std::chrono::microseconds>(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<std::chrono::microseconds>(stop - start).count() << "\n";
{
std::stringstream out;
out << "Dirty mark time: " << std::chrono::duration_cast<std::chrono::microseconds>(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<NumAtomCell &>(*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<StrAtomCell &>(*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<std::chrono::microseconds>(stop - start).count() << "\n";
{
std::stringstream out;
out << "Sweep time: " << std::chrono::duration_cast<std::chrono::microseconds>(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<std::chrono::microseconds>(gcstop - gcstart).count() << "\n";
{
std::stringstream out;
out << "GC total time: " << std::chrono::duration_cast<std::chrono::microseconds>(gcstop - gcstart).count() << "\n";
std::cout << out.str();
}
{

View File

@@ -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) {

View File

@@ -6,6 +6,7 @@
#include <set>
#include <utility>
#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);
}

View File

@@ -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)

96
test/vm/CompilerTest.cpp Normal file
View File

@@ -0,0 +1,96 @@
//
// Created by Stepan Usatiuk on 27.12.2023.
//
#include <gtest/gtest.h>
#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");
}

View File

@@ -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();