mirror of
https://github.com/usatiuk/psil.git
synced 2025-10-28 10:47:49 +01:00
almost working something
This commit is contained in:
21
clitests/coffee.psil
Normal file
21
clitests/coffee.psil
Normal 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
3
clitests/coffee.res
Normal file
@@ -0,0 +1,3 @@
|
||||
0
|
||||
2
|
||||
3
|
||||
@@ -20,6 +20,7 @@ for FILE in *.psil; do
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "$FILE OK"
|
||||
rm $FILE.res
|
||||
done
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
Reference in New Issue
Block a user