From 7ae83db7285a89f40c5bb6c81ac517f2119a8b75 Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Wed, 3 Jan 2024 16:27:50 +0100 Subject: [PATCH] Globals! --- src/logger/include/Logger.h | 7 ++--- src/vm/include/Command.h | 1 + src/vm/include/VM.h | 4 ++- src/vm/src/Compiler.cpp | 21 ++++++++----- src/vm/src/VM.cpp | 4 ++- test/vm/CompilerTest.cpp | 62 +++++++++++++++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 15 deletions(-) diff --git a/src/logger/include/Logger.h b/src/logger/include/Logger.h index 758fba9..f52a55a 100644 --- a/src/logger/include/Logger.h +++ b/src/logger/include/Logger.h @@ -14,7 +14,7 @@ class Logger { public: - enum LogLevel { DISABLED = 0, ERROR = 1, INFO = 2, DEBUG = 3, TRACE = 4 }; + enum LogLevel { ALWAYS = 0, ERROR = 1, INFO = 2, DEBUG = 3, TRACE = 4 }; static void log(const std::string &tag, const std::string &what, int level); static void log(const std::string &tag, const std::function &fn, int level); @@ -34,10 +34,7 @@ private: std::unordered_map _levels; static inline std::unordered_map _level_names{ - {ERROR, "ERROR"}, - {INFO, "INFO"}, - {DEBUG, "DEBUG"}, - {TRACE, "TRACE"}, + {ALWAYS, "ALWAYS"}, {ERROR, "ERROR"}, {INFO, "INFO"}, {DEBUG, "DEBUG"}, {TRACE, "TRACE"}, }; int _default_level = 1; std::chrono::time_point _start_time = std::chrono::high_resolution_clock::now(); diff --git a/src/vm/include/Command.h b/src/vm/include/Command.h index 4c79d53..1ce355f 100644 --- a/src/vm/include/Command.h +++ b/src/vm/include/Command.h @@ -36,6 +36,7 @@ namespace Command { READ = 20, CONS = 21, + LDG = 22, }; static inline std::unordered_map str_to_cmd{ diff --git a/src/vm/include/VM.h b/src/vm/include/VM.h index 6eb9577..20b4348 100644 --- a/src/vm/include/VM.h +++ b/src/vm/include/VM.h @@ -27,8 +27,10 @@ public: void step(); private: + Handle _globals_names = Handle::cons(Handle::cons(nullptr, nullptr), nullptr); + Handle _globals_vals = Handle::cons(nullptr, nullptr); Handle _s = Handle::cons(nullptr, nullptr); - Handle _e = Handle::cons(nullptr, nullptr); + Handle _e = Handle::cons(_globals_vals, nullptr); Handle _c = Handle::cons(nullptr, nullptr); Handle _d = Handle::cons(nullptr, nullptr); bool _stop = false; diff --git a/src/vm/src/Compiler.cpp b/src/vm/src/Compiler.cpp index 05524d3..4b95ef4 100644 --- a/src/vm/src/Compiler.cpp +++ b/src/vm/src/Compiler.cpp @@ -69,6 +69,10 @@ Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { 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() == "define") { + fake_env.car().append(Handle(std::string(cdr.car().car().strval()))); + out.append(Handle(LDG)); + out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car().cdr(), fake_env), Handle(RET))); } else if (car.strval() == "let" || car.strval() == "letrec") { std::vector> argBody; @@ -87,17 +91,18 @@ Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { } Handle newenv = Handle::cons(argNames, fake_env); - if (car.strval() == "let") out.splice(compileArgsList(argBodies, fake_env)); - else if (car.strval() == "letrec") { + if (car.strval() == "let") { + out.splice(compileArgsList(argBodies, fake_env)); + out.append(Handle(LDF)); + out.append(compile(body, newenv, Handle(RET))); + out.append(Handle(AP)); + } 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(LDF)); + out.append(compile(body, newenv, Handle(RET))); out.append(Handle(RAP)); + } } else { out.splice(compileArgsList(cdr, fake_env)); diff --git a/src/vm/src/VM.cpp b/src/vm/src/VM.cpp index 4768177..07757fa 100644 --- a/src/vm/src/VM.cpp +++ b/src/vm/src/VM.cpp @@ -129,7 +129,7 @@ void VM::step() { _outstream << _s.pop().val(); } else if (poppedCmd == EVAL) { Handle code = _s.pop(); - Handle newc = Compiler::compile(code, nullptr); + Handle newc = Compiler::compile(code, _globals_names); Logger::log( "Compiler", [&](std::ostream &out) { @@ -140,6 +140,8 @@ void VM::step() { Logger::DEBUG); newc.splice(_c); _c = newc; + } else if (poppedCmd == LDG) { + _globals_vals.append(Handle::cons(_c.pop(), _e)); } else if (poppedCmd == PRINT) { _outstream << _s.pop(); } else if (poppedCmd == READ) { diff --git a/test/vm/CompilerTest.cpp b/test/vm/CompilerTest.cpp index 8bcfe98..e97767a 100644 --- a/test/vm/CompilerTest.cpp +++ b/test/vm/CompilerTest.cpp @@ -94,4 +94,66 @@ TEST(CompilerTest, RecursiveFn) { } ssout.flush(); EXPECT_EQ(ssout.str(), "55"); +} + +TEST(CompilerTest, GlobalDefine) { + std::stringstream ssin; + std::stringstream ssout; + { + + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC (define (one) 1) EVAL LDC (one) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "1"); +} + + +TEST(CompilerTest, GlobalDefineFn) { + std::stringstream ssin; + std::stringstream ssout; + { + + VM vm(ssin, ssout); + Parser parser; + parser.loadStr("(LDC (define (one x y) (+ x y)) EVAL LDC (one 2 3) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "5"); +} + +TEST(CompilerTest, GlobalDefineFnMulti) { + 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(), "6"); +} + +TEST(CompilerTest, GlobalDefineFnRec) { + std::stringstream ssin; + std::stringstream ssout; + { + + VM vm(ssin, ssout); + Parser parser; + parser.loadStr( + "(LDC (define (fib n) (if n (if (+ n -1) (+ (fib (+ n -1)) (fib(+ n -2))) 1) 0) ) EVAL LDC (fib 10) EVAL PRINT STOP)"); + vm.loadControl(parser.parseExpr()); + vm.run(); + } + ssout.flush(); + EXPECT_EQ(ssout.str(), "55"); } \ No newline at end of file