almost working something

This commit is contained in:
2024-01-03 20:31:37 +01:00
parent 7c54d16273
commit 2db8b5984f
9 changed files with 262 additions and 34 deletions

21
clitests/coffee.psil Normal file
View File

@@ -0,0 +1,21 @@
(define (getmax a b)
(if (> a b) a b)
)
(define (coffee-shop-impl times last cur max)
(if (= times (nil))
(getmax cur max)
(if (= last (car times))
(coffee-shop-impl (cdr times) last (+ cur 1) max)
(coffee-shop-impl (cdr times) (car times) 1 (getmax cur max))
)
)
)
(define (coffee-shop times)
(coffee-shop-impl times (nil) 0 0)
)
(coffee-shop (nil))
(coffee-shop (quote( (8 0) (8 10) (8 10) (8 45) )))
(coffee-shop (quote( (8 12) (10 11) (10 11) (15 15) (15 15) (15 15) (22 22) (22 22) (22 59) )))

3
clitests/coffee.res Normal file
View File

@@ -0,0 +1,3 @@
0
2
3

View File

@@ -20,6 +20,7 @@ for FILE in *.psil; do
continue
fi
echo "$FILE OK"
rm $FILE.res
done

View File

@@ -9,6 +9,7 @@
#include <cassert>
#include <cstdint>
#include <ostream>
#include <set>
#include <sstream>
#include <string>
#include <utility>
@@ -53,21 +54,59 @@ struct ConsCell : public Cell {
std::atomic<Cell *> _car = nullptr;
std::atomic<Cell *> _cdr = nullptr;
void print(std::ostream &out) override {
void print_cons(std::ostream &out, std::set<Cell *> &seen) {
std::stringstream res;
if (_car) {
if (_car.load()->_type == CellType::CONS) {
res << "(";
_car.load()->print(res);
res << ")";
if (seen.find(_car) == seen.end()) {
res << "(";
seen.emplace(_car.load());
dynamic_cast<ConsCell &>(*_car.load()).print_cons(res, seen);
res << ")";
} else {
res << "(recursive)";
}
} else {
_car.load()->print(res);
}
}
if (_cdr) {
if (_cdr.load()->_type == CellType::CONS) {
res << " ";
if (seen.find(_cdr) == seen.end()) {
res << " ";
seen.emplace(_cdr.load());
dynamic_cast<ConsCell &>(*_cdr.load()).print_cons(res, seen);
} else {
res << " recursive";
}
} else {
res << ".";
_cdr.load()->print(res);
}
}
out << res.str();
}
void print(std::ostream &out) override {
std::stringstream res;
std::set<Cell *> seen;
if (_car) {
if (_car.load()->_type == CellType::CONS) {
res << "(";
seen.emplace(_car.load());
dynamic_cast<ConsCell &>(*_car.load()).print_cons(res, seen);
res << ")";
} else {
_car.load()->print(res);
}
} else {
res << "null ";
}
if (_cdr) {
if (_cdr.load()->_type == CellType::CONS) {
res << " ";
seen.emplace(_cdr.load());
dynamic_cast<ConsCell &>(*_cdr.load()).print_cons(res, seen);
} else {
res << ".";
_cdr.load()->print(res);

View File

@@ -30,14 +30,15 @@ public:
} else if (_target->_type == CellType::STRATOM) {
return dynamic_cast<StrAtomCell &>(*_target)._val == dynamic_cast<StrAtomCell &>(*rhs._target)._val;
}
}
} else if (null() && rhs.null())
return true;
return false;
}
static Handle cons(const Handle &car, const Handle &cdr);
Handle car() { return dynamic_cast<ConsCell &>(*_target)._car.load(); }
Handle cdr() { return dynamic_cast<ConsCell &>(*_target)._cdr.load(); }
Handle car() const { return dynamic_cast<ConsCell &>(*_target)._car.load(); }
Handle cdr() const { return dynamic_cast<ConsCell &>(*_target)._cdr.load(); }
CellValType val() { return dynamic_cast<NumAtomCell &>(*_target)._val; }
std::string_view strval() { return dynamic_cast<StrAtomCell &>(*_target)._val; }
@@ -48,7 +49,7 @@ public:
bool atom() const { return type() != CellType::CONS; }
bool null() {
bool null() const {
if (!_target) return true;
if (type() == CellType::CONS && car() == nullptr && cdr() == nullptr) return true;
return false;

View File

@@ -4,37 +4,55 @@
#include "Compiler.h"
#include "Command.h"
#include <functional>
#include <stack>
#include <string>
#include "Command.h"
#include "Logger.h"
using namespace Command;
static std::unordered_map<std::string_view, CommandE> builtins{{"+", ADD}, {"-", SUB}, {"cons", CONS}, {"car", CAR},
{"cdr", CDR}, {"=", EQ}, {">", GT}, {"<", LT}};
static std::unordered_map<std::string_view, CommandE> builtins{{"+", ADD}, {"-", SUB}, {"cons", CONS}, {"car", CAR}, {"cdr", CDR},
{"=", EQ}, {">", GT}, {"<", LT}, {"nil", NIL}};
Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffix) {
Handle out;
std::function<Handle(Handle)> compileArgsRaw = [&](Handle args) {
Handle out;
std::stack<Handle> rev;
while (!args.null()) {
out.splice(compile(args.car(), fake_env));
rev.push(args.car());
args = args.cdr();
}
while (!rev.empty()) {
out.splice(compile(rev.top(), fake_env));
rev.pop();
}
return out;
};
std::function<Handle(Handle, Handle)> compileArgsList = [&](Handle args, Handle env) {
Handle out;
out.append(make_cmd(NIL));
std::stack<Handle> rev;
while (!args.null()) {
out.splice(compile(args.car(), env));
out.append(make_cmd(CONS));
rev.push(args.car());
args = args.cdr();
}
while (!args.null()) {
rev.push(args.car());
args = args.cdr();
}
while (!rev.empty()) {
out.splice(compile(rev.top(), env));
out.append(make_cmd(CONS));
rev.pop();
}
return out;
};
@@ -60,7 +78,10 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi
Handle car = expr.car();
Handle cdr = expr.cdr();
if (car.atom()) {
if (builtins.find(car.strval()) != builtins.end()) {
if (car.strval() == "quote") {
out.append(make_cmd(LDC));
out.splice(cdr);
} else if (builtins.find(car.strval()) != builtins.end()) {
out.splice(compileArgsRaw(cdr));
out.append(make_cmd(builtins.at(car.strval())));
} else if (car.strval() == "read") {
@@ -78,8 +99,6 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi
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<std::pair<Handle, Handle>> argBody;
Handle definitions = cdr.car();
Handle argNames;
@@ -88,7 +107,6 @@ Handle Compiler::compile(const Handle &src, Handle fake_env, const Handle &suffi
Handle body = cdr.cdr().car();
while (!definitions.null()) {
argBody.emplace_back(definitions.car().car(), definitions.car().cdr().car());
argNames.append(definitions.car().car());
argBodies.append(definitions.car().cdr().car());
definitions = definitions.cdr();

View File

@@ -29,6 +29,10 @@ Handle Parser::parseExpr() {
return out;
}
if (_tokenizer.peek() == ")") {
token = _tokenizer.peek();
continue;
}
out.append(parseExpr());
token = _tokenizer.peek();
}
@@ -37,7 +41,7 @@ Handle Parser::parseExpr() {
} else {
token = _tokenizer.getNext();
if (token.find_first_not_of("0123456789") == std::string::npos ||
(token.length() > 1 && token.at(0) == '0' && token.find_first_not_of("0123456789", 1) == std::string::npos)) {
(token.length() > 1 && token.at(0) == '-' && token.find_first_not_of("0123456789", 1) == std::string::npos)) {
CellValType val = std::stoi(token);
return Handle::makeNumCell(val);
} else {

View File

@@ -23,6 +23,19 @@ void VM::step() {
Handle poppedH = _c.pop();
// as to not complicate parser for tests...
CellValType poppedCmd = poppedH.type() == CellType::STRATOM ? str_to_cmd.at(poppedH.strval()) : poppedH.val();
Logger::log(
"VM",
[&](std::ostream &out) {
out << "Executing " << cmd_to_str.at(poppedCmd) << "\n";
if (!_s.null()) out << "s:" << _s << "\n";
if (!_e.null()) out << "e:" << _e << "\n";
if (!_c.null()) out << "c:" << _c << "\n";
if (!_d.null()) out << "d:" << _d << "\n";
},
Logger::TRACE);
if (poppedCmd == NIL) {
_s.push(nullptr);
} else if (poppedCmd == LDC) {
@@ -115,17 +128,17 @@ void VM::step() {
} else if (poppedCmd == SUB) {
CellValType a1 = _s.pop().val();
CellValType a2 = _s.pop().val();
_s.push(a2 - a1);
_s.push(a1 - a2);
} else if (poppedCmd == EQ) {
_s.push(_s.pop() == _s.pop() ? 1 : 0);
} else if (poppedCmd == LT) {
CellValType a1 = _s.pop().val();
CellValType a2 = _s.pop().val();
_s.push(a2 < a1 ? 1 : 0);
_s.push(a1 < a2 ? 1 : 0);
} else if (poppedCmd == GT) {
CellValType a1 = _s.pop().val();
CellValType a2 = _s.pop().val();
_s.push(a2 > a1 ? 1 : 0);
_s.push(a1 > a2 ? 1 : 0);
} else if (poppedCmd == CAR) {
_s.push(_s.pop().car());
} else if (poppedCmd == CDR) {
@@ -159,7 +172,14 @@ void VM::step() {
} else if (poppedCmd == LDG) {
_globals_vals.append(Handle::cons(_c.pop(), _e));
} else if (poppedCmd == PRINT) {
if (!_s.null()) _outstream << _s.pop() << std::endl;
if (!_s.null()) {
Handle val = _s.pop();
bool cons = !val.atom();
if (cons) _outstream << "(";
_outstream << val;
if (cons) _outstream << ")";
_outstream << std::endl;
}
} else if (poppedCmd == READ) {
std::string read;
std::getline(_instream, read);
@@ -169,4 +189,16 @@ void VM::step() {
} else {
assert(false);
}
Logger::log(
"VM",
[&](std::ostream &out) {
out << "Executed " << cmd_to_str.at(poppedCmd) << "\n";
if (!_s.null()) out << "s:" << _s << "\n";
if (!_e.null()) out << "e:" << _e << "\n";
if (!_c.null()) out << "c:" << _c << "\n";
if (!_d.null()) out << "d:" << _d << "\n";
},
Logger::TRACE);
}

View File

@@ -37,7 +37,7 @@ TEST(CompilerTest, BasicHello) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "3");
EXPECT_EQ(ssout.str(), "3\n");
}
TEST(CompilerTest, BasicLet) {
@@ -52,7 +52,7 @@ TEST(CompilerTest, BasicLet) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "1");
EXPECT_EQ(ssout.str(), "1\n");
}
TEST(CompilerTest, BasicFn) {
@@ -67,9 +67,48 @@ TEST(CompilerTest, BasicFn) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "5");
EXPECT_EQ(ssout.str(), "5\n");
}
TEST(CompilerTest, BasicFn2) {
std::stringstream ssin;
std::stringstream ssout;
{
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(), "-1\n");
}
TEST(CompilerTest, MultiLet) {
std::stringstream ssin;
std::stringstream ssout;
{
VM vm(ssin, ssout);
Parser parser;
parser.loadStr("(LDC (let ((plfn (lambda (a b) (- a b))) (plfn2 (lambda (a b) (- b a)))) (plfn 2 3)) EVAL PRINT STOP)");
vm.loadControl(parser.parseExpr());
vm.run();
}
{
VM vm(ssin, ssout);
Parser parser;
parser.loadStr("(LDC (let ((plfn (lambda (a b) (- a b))) (plfn2 (lambda (a b) (- b a)))) (plfn2 2 3)) EVAL PRINT STOP)");
vm.loadControl(parser.parseExpr());
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "-1\n1\n");
}
TEST(CompilerTest, BasicFnIfT) {
std::stringstream ssin;
std::stringstream ssout;
@@ -82,7 +121,7 @@ TEST(CompilerTest, BasicFnIfT) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "1");
EXPECT_EQ(ssout.str(), "1\n");
}
TEST(CompilerTest, BasicFnIfF) {
std::stringstream ssin;
@@ -96,7 +135,7 @@ TEST(CompilerTest, BasicFnIfF) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "2");
EXPECT_EQ(ssout.str(), "2\n");
}
TEST(CompilerTest, RecursiveFn) {
std::stringstream ssin;
@@ -111,7 +150,7 @@ TEST(CompilerTest, RecursiveFn) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "55");
EXPECT_EQ(ssout.str(), "55\n");
}
TEST(CompilerTest, GlobalDefine) {
@@ -126,7 +165,7 @@ TEST(CompilerTest, GlobalDefine) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "1");
EXPECT_EQ(ssout.str(), "1\n");
}
@@ -142,7 +181,61 @@ TEST(CompilerTest, GlobalDefineFn) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "5");
EXPECT_EQ(ssout.str(), "5\n");
}
TEST(CompilerTest, GlobalDefineFnQuote) {
std::stringstream ssin;
std::stringstream ssout;
{
VM vm(ssin, ssout);
Parser parser;
parser.loadStr("(LDC (define (one) (quote (1 2))) EVAL LDC (one) EVAL PRINT STOP)");
vm.loadControl(parser.parseExpr());
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "(1 2)\n");
}
TEST(CompilerTest, GlobalDefineFnCar) {
std::stringstream ssin;
std::stringstream ssout;
{
VM vm(ssin, ssout);
Parser parser;
parser.loadStr(
"(LDC (define (carr l) (car l)) EVAL LDC (carr (quote (1 2))) EVAL PRINT LDC (carr (cdr (quote (1 2)))) EVAL PRINT STOP)");
vm.loadControl(parser.parseExpr());
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "1\n2\n");
}
TEST(CompilerTest, GlobalDefineFnEq) {
std::stringstream ssin;
std::stringstream ssout;
{
VM vm(ssin, ssout);
Parser parser;
parser.loadStr("(LDC (define (eqtest l) (= l ())) EVAL LDC (eqtest (quote ())) EVAL PRINT LDC (eqtest (nil)) EVAL PRINT STOP)");
vm.loadControl(parser.parseExpr());
vm.run();
}
{
VM vm(ssin, ssout);
Parser parser;
parser.loadStr("(LDC (define (eqtest l) (= l (nil))) EVAL LDC (eqtest (quote ())) EVAL PRINT LDC (eqtest (nil)) EVAL PRINT STOP)");
vm.loadControl(parser.parseExpr());
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "1\n1\n1\n1\n");
}
TEST(CompilerTest, GlobalDefineFnMulti) {
@@ -157,9 +250,25 @@ TEST(CompilerTest, GlobalDefineFnMulti) {
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "6");
EXPECT_EQ(ssout.str(), "6\n");
}
TEST(CompilerTest, GlobalDefineFnMultiTwo) {
std::stringstream ssin;
std::stringstream ssout;
{
VM vm(ssin, ssout);
Parser parser;
parser.loadStr("(LDC (define (one x y) (- x y)) EVAL LDC (define (two x y) (one (+ x 1) y)) EVAL LDC (two 2 3) EVAL PRINT STOP)");
vm.loadControl(parser.parseExpr());
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "0\n");
}
TEST(CompilerTest, GlobalDefineFnRec) {
std::stringstream ssin;
std::stringstream ssout;
@@ -176,5 +285,5 @@ TEST(CompilerTest, GlobalDefineFnRec) {
Options::set_bool("command_strs", true);
Logger::set_level("MemoryContext", Options::get_int("default_log_level"));
ssout.flush();
EXPECT_EQ(ssout.str(), "6765");
EXPECT_EQ(ssout.str(), "6765\n");
}