add experimental REPL (cpp)

This commit is contained in:
ValKmjolnir 2023-08-27 17:46:10 +08:00
parent ae5c76ecd5
commit a801669888
8 changed files with 195 additions and 17 deletions

View File

@ -38,7 +38,8 @@ set(NASAL_OBJECT_SOURCE_FILE
${CMAKE_SOURCE_DIR}/src/nasal_parse.cpp
${CMAKE_SOURCE_DIR}/src/nasal_vm.cpp
${CMAKE_SOURCE_DIR}/src/optimizer.cpp
${CMAKE_SOURCE_DIR}/src/symbol_finder.cpp)
${CMAKE_SOURCE_DIR}/src/symbol_finder.cpp
${CMAKE_SOURCE_DIR}/src/repl.cpp)
add_library(nasal-object STATIC ${NASAL_OBJECT_SOURCE_FILE})
target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src)

View File

@ -23,7 +23,8 @@ NASAL_HEADER=\
src/math_lib.h\
src/dylib_lib.h\
src/unix_lib.h\
src/coroutine.h
src/coroutine.h\
src/repl.h
NASAL_OBJECT=\
build/nasal_err.o\
@ -49,6 +50,7 @@ NASAL_OBJECT=\
build/coroutine.o\
build/nasal_vm.o\
build/nasal_dbg.o\
build/repl.o\
build/main.o
# for test
@ -67,6 +69,9 @@ build/main.o: $(NASAL_HEADER) src/main.cpp | build
build/nasal_misc.o: src/nasal.h src/nasal_misc.cpp | build
$(CXX) -std=$(STD) -c -O3 src/nasal_misc.cpp -fno-exceptions -fPIC -o build/nasal_misc.o -I .
build/repl.o: src/nasal.h src/repl.h src/repl.cpp | build
$(CXX) -std=$(STD) -c -O3 src/repl.cpp -fno-exceptions -fPIC -o build/repl.o -I .
build/nasal_err.o: src/nasal.h src/nasal_err.h src/nasal_err.cpp | build
$(CXX) -std=$(STD) -c -O3 src/nasal_err.cpp -fno-exceptions -fPIC -o build/nasal_err.o -I .

View File

@ -11,6 +11,7 @@
#include "nasal_codegen.h"
#include "nasal_vm.h"
#include "nasal_dbg.h"
#include "repl.h"
#include <unordered_map>
#include <thread>
@ -53,6 +54,7 @@ std::ostream& help(std::ostream& out) {
<< " --prof | show profiling result, available under debug mode.\n"
<< " --prof-all | show profiling result of all files,"
<< "available under debug mode.\n"
<< " -r, --repl | use repl interpreter(experimental).\n"
<< "file:\n"
<< " <filename> | execute file.\n"
<< "argv:\n"
@ -129,9 +131,8 @@ void execute(
ld.link(parse, file, cmd&VM_DETAIL).chkerr();
// optimizer does simple optimization on ast
auto opt = new optimizer;
auto opt = std::unique_ptr<optimizer>(new optimizer);
opt->do_optimization(parse.tree());
delete opt;
if (cmd&VM_AST) {
auto dumper = std::unique_ptr<ast_dumper>(new ast_dumper);
dumper->dump(parse.tree());
@ -178,6 +179,9 @@ i32 main(i32 argc, const char* argv[]) {
std::clog << help;
} else if (s=="-v" || s=="--version") {
std::clog << version;
} else if (s=="-r" || s=="--repl") {
auto repl_module = std::unique_ptr<repl::repl>(new repl::repl);
repl_module->execute();
} else if (s[0]!='-') {
execute(s, {}, VM_EXEC);
} else {

View File

@ -1144,7 +1144,7 @@ void codegen::ret_gen(return_expr* node) {
gen(op_ret, 0, node->get_location());
}
const error& codegen::compile(parse& parse, linker& import, bool repl) {
const error& codegen::compile(parse& parse, linker& import) {
init_native_function();
init_file_map(import.get_file_list());
@ -1157,7 +1157,7 @@ const error& codegen::compile(parse& parse, linker& import, bool repl) {
// search global symbols first
find_symbol(parse.tree());
gen(op_intg, repl? STACK_DEPTH/2:global.size(), parse.tree()->get_location());
gen(op_intg, global.size(), parse.tree()->get_location());
// generate main block
block_gen(parse.tree());

View File

@ -132,7 +132,7 @@ public:
public:
codegen() = default;
const error& compile(parse&, linker&, bool repl = false);
const error& compile(parse&, linker&);
void print(std::ostream&);
void symbol_dump(std::ostream&) const;
};

137
src/repl.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "repl.h"
#include "nasal_lexer.h"
#include "nasal_parse.h"
#include "nasal_import.h"
#include "optimizer.h"
#include "nasal_codegen.h"
#include "nasal_vm.h"
namespace repl {
std::string repl::readline(std::string prompt = ">>> ") {
auto line = std::string("");
std::cout << prompt;
std::getline(std::cin, line,'\n');
return line;
}
void repl::update_temp_file() {
auto content = std::string("");
for(const auto& i : source) {
content += i + "\n";
}
std::ofstream out(".temp.nas", std::ios::binary);
out << content;
}
bool repl::check_need_more_input() {
while(true) {
update_temp_file();
auto nasal_lexer = std::unique_ptr<lexer>(new lexer);
if (nasal_lexer->scan(".temp.nas").geterr()) {
return false;
}
i64 in_curve = 0;
i64 in_bracket = 0;
i64 in_brace = 0;
for(const auto& t : nasal_lexer->result()) {
switch(t.type) {
case tok::lcurve: ++in_curve; break;
case tok::rcurve: --in_curve; break;
case tok::lbracket: ++in_bracket; break;
case tok::rbracket: --in_bracket; break;
case tok::lbrace: ++in_brace; break;
case tok::rbrace: --in_brace; break;
default: break;
}
}
if (!in_curve && !in_bracket && !in_brace) {
break;
}
auto line = readline("... ");
source.back() += "\n" + line;
}
return true;
}
void repl::help() {
std::cout << ".h, .help | show help\n";
std::cout << ".e, .exit | quit the REPL\n";
std::cout << ".q, .quit | quit the REPL\n";
std::cout << ".c, .clear | clear the screen\n";
std::cout << "\n";
}
bool repl::run() {
update_temp_file();
auto nasal_lexer = std::unique_ptr<lexer>(new lexer);
auto nasal_parser = std::unique_ptr<parse>(new parse);
auto nasal_linker = std::unique_ptr<linker>(new linker);
auto nasal_opt = std::unique_ptr<optimizer>(new optimizer);
auto nasal_codegen = std::unique_ptr<codegen>(new codegen);
auto nasal_runtime = std::unique_ptr<vm>(new vm);
if (nasal_lexer->scan(".temp.nas").geterr()) {
return false;
}
if (nasal_parser->compile(*nasal_lexer).geterr()) {
return false;
}
if (nasal_linker->link(*nasal_parser, ".temp.nas", true).geterr()) {
return false;
}
nasal_opt->do_optimization(nasal_parser->tree());
if (nasal_codegen->compile(*nasal_parser, *nasal_linker).geterr()) {
return false;
}
nasal_runtime->run(*nasal_codegen, *nasal_linker, {}, false);
return true;
}
void repl::execute() {
source = {};
std::cout << "Nasal REPL interpreter(experimental).\n";
help();
while(true) {
auto line = readline();
if (!line.length()) {
continue;
}
if (line == ".e" || line == ".exit" || line == ".q" || line == ".quit") {
break;
} else if (line == ".h" || line == ".help") {
help();
continue;
} else if (line == ".c" || line == ".clear") {
std::cout << "\033c";
continue;
} else if (line[0] == "."[0]) {
std::cout << "no such command \"" << line;
std::cout << "\", input \".help\" for help\n";
continue;
}
source.push_back(line);
if (!check_need_more_input()) {
source.pop_back();
continue;
}
if (!run()) {
source.pop_back();
}
std::cout << "\n";
}
}
}

28
src/repl.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include "nasal.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
#include <sstream>
namespace repl {
class repl {
private:
std::vector<std::string> source;
private:
std::string readline(std::string);
bool check_need_more_input();
void update_temp_file();
void help();
bool run();
public:
void execute();
};
}

View File

@ -31,6 +31,9 @@ var count_bracket = func(line) {
while(1) {
var line = readline(">>> ");
if (!size(line)) {
continue;
}
if (line == ".exit" or line == ".quit") {
break;
} elsif (line == ".help") {