From 3bace25d46320dc7f7368ac766fa928cdc19c5bd Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Sat, 23 Dec 2023 14:22:47 +0100 Subject: [PATCH] hopefully correct rap --- src/vm/includes/Cell.h | 3 + src/vm/src/VM.cpp | 58 ++++++++++++++-- test/vm/VMTest.cpp | 146 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 6 deletions(-) diff --git a/src/vm/includes/Cell.h b/src/vm/includes/Cell.h index b35e5f4..71675a5 100644 --- a/src/vm/includes/Cell.h +++ b/src/vm/includes/Cell.h @@ -48,6 +48,9 @@ struct CommandCell : public IntCell { READCHAR = 201, PUTCHAR = 202, + PUTNUM = 203, + + CONS = 301, END = 1000 }; diff --git a/src/vm/src/VM.cpp b/src/vm/src/VM.cpp index 664caeb..73bd488 100644 --- a/src/vm/src/VM.cpp +++ b/src/vm/src/VM.cpp @@ -13,6 +13,7 @@ void VM::run() { void VM::step() { CommandCell *popped = dynamic_cast(pop(_c)); + assert(popped); switch (popped->intToCmd()) { case CommandCell::CommandNum::NIL: { @@ -25,8 +26,11 @@ void VM::step() { } case CommandCell::CommandNum::LD: { ConsCell *popped2 = dynamic_cast(pop(_c)); + assert(popped2); + assert(dynamic_cast(popped2->_car)); int64_t frame = dynamic_cast(popped2->_car)->_val; + assert(dynamic_cast(popped2->_cdr)); int64_t arg = dynamic_cast(popped2->_cdr)->_val; assert(frame > 0); @@ -36,11 +40,13 @@ void VM::step() { for (int i = 1; i < frame; i++) { curFrame = dynamic_cast(_e->_cdr); + assert(curFrame); } ConsCell *curArg = dynamic_cast(curFrame->_car); for (int i = 1; i < arg; i++) { curArg = dynamic_cast(curArg->_cdr); + assert(curArg); } push(_s, curArg->_car); @@ -49,8 +55,11 @@ void VM::step() { } case CommandCell::CommandNum::SEL: { IntCell *popped2 = dynamic_cast(pop(_s)); + assert(popped2); ConsCell *ct = dynamic_cast(pop(_c)); + assert(ct); ConsCell *cf = dynamic_cast(pop(_c)); + assert(cf); ConsCell *ret = _c; push(_d, ret); if (popped2->_val > 0) { @@ -63,30 +72,37 @@ void VM::step() { } case CommandCell::CommandNum::JOIN: { ConsCell *ret = dynamic_cast(pop(_d)); + assert(ret); _c = ret; break; } case CommandCell::CommandNum::LDF: { ConsCell *fn = dynamic_cast(pop(_c)); + assert(fn); push(_s, makeCell(fn, _e)); break; } case CommandCell::CommandNum::AP: { ConsCell *closure = dynamic_cast(pop(_s)); + assert(closure); ConsCell *args = dynamic_cast(pop(_s)); + assert(args); push(_d, _s); push(_d, _e); + assert(_c); push(_d, _c); _s = makeCell(); _c = dynamic_cast(closure->_car); + assert(_c); _e = dynamic_cast(closure->_cdr); push(_e, args); break; } case CommandCell::CommandNum::RET: { ConsCell *c = dynamic_cast(pop(_d)); + assert(c); ConsCell *e = dynamic_cast(pop(_d)); ConsCell *s = dynamic_cast(pop(_d)); @@ -101,9 +117,28 @@ void VM::step() { break; } case CommandCell::CommandNum::DUM: { + push(_e, nullptr); break; } case CommandCell::CommandNum::RAP: { + ConsCell *closure = dynamic_cast(pop(_s)); + assert(closure); + ConsCell *args = dynamic_cast(pop(_s)); + assert(args); + + push(_d, _s); + ConsCell *e = dynamic_cast(_e->_cdr); + push(_d, e); + assert(_c); + push(_d, _c); + + _s = makeCell(); + _c = dynamic_cast(closure->_car); + assert(_c); + ConsCell *fnenv = dynamic_cast(closure->_cdr); + assert(fnenv); + assert(_e == fnenv); + fnenv->_car = args; break; } case CommandCell::CommandNum::STOP: { @@ -112,13 +147,22 @@ void VM::step() { } case CommandCell::CommandNum::ADD: { IntCell *a1 = dynamic_cast(pop(_s)); + assert(a1); IntCell *a2 = dynamic_cast(pop(_s)); + assert(a2); push(_s, makeCell(a1->_val + a2->_val)); break; } case CommandCell::CommandNum::SUB: { break; } + case CommandCell::CommandNum::CONS: { + Cell *a1 = pop(_s); + Cell *a2 = pop(_s); + + push(_s, cons(a1, a2)); + break; + } case CommandCell::CommandNum::READCHAR: { char c; _instream >> c; @@ -127,9 +171,16 @@ void VM::step() { } case CommandCell::CommandNum::PUTCHAR: { IntCell *popped2 = dynamic_cast(pop(_s)); + assert(popped2); _outstream << (char) popped2->_val; break; } + case CommandCell::CommandNum::PUTNUM: { + IntCell *popped2 = dynamic_cast(pop(_s)); + assert(popped2); + _outstream << popped2->_val; + break; + } case CommandCell::CommandNum::END: { assert(false); break; @@ -140,9 +191,4 @@ void VM::step() { } -VM::VM(std::istream &instream, std::ostream &outstream) : _instream(instream), _outstream(outstream) { - _s = dynamic_cast(makeCell(nullptr)); - _e = dynamic_cast(makeCell(nullptr)); - _c = dynamic_cast(makeCell(nullptr)); - _d = dynamic_cast(makeCell(nullptr)); -} +VM::VM(std::istream &instream, std::ostream &outstream) : _instream(instream), _outstream(outstream) {} diff --git a/test/vm/VMTest.cpp b/test/vm/VMTest.cpp index 442847f..0667fb1 100644 --- a/test/vm/VMTest.cpp +++ b/test/vm/VMTest.cpp @@ -92,4 +92,150 @@ TEST(VMTest, SimpleFunction) { ssout.flush(); EXPECT_EQ(ssout.str(), "3"); +} + +TEST(VMTest, RecursiveFunction) { + std::stringstream ssin; + std::stringstream ssout; + { + VM vm(ssin, ssout); + vm.appendCommand(vm.makeCell(CommandCell::CommandNum::STOP)); + + vm.appendCommand(vm.makeCell(CommandCell::CommandNum::RAP)); + + // Fib function + ConsCell *fibfn = vm.makeCell(vm.makeCell(CommandCell::CommandNum::RET)); + + // 0 case + ConsCell *zcase = vm.makeCell(vm.makeCell(CommandCell::CommandNum::JOIN)); + vm.push(zcase, vm.makeCell(0)); + vm.push(zcase, vm.makeCell(CommandCell::CommandNum::LDC)); + + // 1 case + ConsCell *ocase = vm.makeCell(vm.makeCell(CommandCell::CommandNum::JOIN)); + vm.push(ocase, vm.makeCell(1)); + vm.push(ocase, vm.makeCell(CommandCell::CommandNum::LDC)); + + // >1 case + ConsCell *gocase = vm.makeCell(vm.makeCell(CommandCell::CommandNum::JOIN)); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::ADD)); + + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::AP)); + vm.push(gocase, vm.makeCell(vm.makeCell(2), vm.makeCell(1))); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::LD)); + + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::CONS)); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::ADD)); + vm.push(gocase, vm.makeCell(-2)); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(gocase, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::LD)); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::NIL)); + + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::AP)); + vm.push(gocase, vm.makeCell(vm.makeCell(2), vm.makeCell(1))); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::LD)); + + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::CONS)); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::ADD)); + vm.push(gocase, vm.makeCell(-1)); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(gocase, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::LD)); + vm.push(gocase, vm.makeCell(CommandCell::CommandNum::NIL)); + + // >=1 case + ConsCell *geocase = vm.makeCell(vm.makeCell(CommandCell::CommandNum::JOIN)); + vm.push(geocase, ocase); + vm.push(geocase, gocase); + vm.push(geocase, vm.makeCell(CommandCell::CommandNum::SEL)); + vm.push(geocase, vm.makeCell(CommandCell::CommandNum::ADD)); + vm.push(geocase, vm.makeCell(-1)); + vm.push(geocase, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(geocase, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(geocase, vm.makeCell(CommandCell::CommandNum::LD)); + + vm.push(fibfn, zcase); + vm.push(fibfn, geocase); + vm.push(fibfn, vm.makeCell(CommandCell::CommandNum::SEL)); + vm.push(fibfn, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(fibfn, vm.makeCell(CommandCell::CommandNum::LD)); + + // Fib caller function + ConsCell *fibcallfn = vm.makeCell(vm.makeCell(CommandCell::CommandNum::RET)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::PUTNUM)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::PUTCHAR)); + vm.push(fibcallfn, vm.makeCell(' ')); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::AP)); + vm.push(fibcallfn, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LD)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::CONS)); + vm.push(fibcallfn, vm.makeCell(20)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::NIL)); + + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::PUTCHAR)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::ADD)); + vm.push(fibcallfn, vm.makeCell('0')); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::AP)); + vm.push(fibcallfn, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LD)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::CONS)); + vm.push(fibcallfn, vm.makeCell(6)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::NIL)); + + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::PUTCHAR)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::ADD)); + vm.push(fibcallfn, vm.makeCell('0')); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::AP)); + vm.push(fibcallfn, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LD)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::CONS)); + vm.push(fibcallfn, vm.makeCell(5)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::NIL)); + + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::PUTCHAR)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::ADD)); + vm.push(fibcallfn, vm.makeCell('0')); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::AP)); + vm.push(fibcallfn, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LD)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::CONS)); + vm.push(fibcallfn, vm.makeCell(4)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::NIL)); + + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::PUTCHAR)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::ADD)); + vm.push(fibcallfn, vm.makeCell('0')); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::AP)); + vm.push(fibcallfn, vm.makeCell(vm.makeCell(1), vm.makeCell(1))); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LD)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::CONS)); + vm.push(fibcallfn, vm.makeCell(3)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::LDC)); + vm.push(fibcallfn, vm.makeCell(CommandCell::CommandNum::NIL)); + + + vm.appendCommand(fibcallfn); + vm.appendCommand(vm.makeCell(CommandCell::CommandNum::LDF)); + + vm.appendCommand(vm.makeCell(CommandCell::CommandNum::CONS)); + vm.appendCommand(fibfn); + vm.appendCommand(vm.makeCell(CommandCell::CommandNum::LDF)); + vm.appendCommand(vm.makeCell(CommandCell::CommandNum::NIL)); + + vm.appendCommand(vm.makeCell(CommandCell::CommandNum::DUM)); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "2358 6765"); + } \ No newline at end of file