✨ add experimental REPL (cpp)
This commit is contained in:
parent
ae5c76ecd5
commit
a801669888
|
@ -38,7 +38,8 @@ set(NASAL_OBJECT_SOURCE_FILE
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_parse.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_parse.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_vm.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_vm.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/optimizer.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})
|
add_library(nasal-object STATIC ${NASAL_OBJECT_SOURCE_FILE})
|
||||||
target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
|
7
makefile
7
makefile
|
@ -23,7 +23,8 @@ NASAL_HEADER=\
|
||||||
src/math_lib.h\
|
src/math_lib.h\
|
||||||
src/dylib_lib.h\
|
src/dylib_lib.h\
|
||||||
src/unix_lib.h\
|
src/unix_lib.h\
|
||||||
src/coroutine.h
|
src/coroutine.h\
|
||||||
|
src/repl.h
|
||||||
|
|
||||||
NASAL_OBJECT=\
|
NASAL_OBJECT=\
|
||||||
build/nasal_err.o\
|
build/nasal_err.o\
|
||||||
|
@ -49,6 +50,7 @@ NASAL_OBJECT=\
|
||||||
build/coroutine.o\
|
build/coroutine.o\
|
||||||
build/nasal_vm.o\
|
build/nasal_vm.o\
|
||||||
build/nasal_dbg.o\
|
build/nasal_dbg.o\
|
||||||
|
build/repl.o\
|
||||||
build/main.o
|
build/main.o
|
||||||
|
|
||||||
# for test
|
# 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
|
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 .
|
$(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
|
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 .
|
$(CXX) -std=$(STD) -c -O3 src/nasal_err.cpp -fno-exceptions -fPIC -o build/nasal_err.o -I .
|
||||||
|
|
||||||
|
|
28
src/main.cpp
28
src/main.cpp
|
@ -11,21 +11,22 @@
|
||||||
#include "nasal_codegen.h"
|
#include "nasal_codegen.h"
|
||||||
#include "nasal_vm.h"
|
#include "nasal_vm.h"
|
||||||
#include "nasal_dbg.h"
|
#include "nasal_dbg.h"
|
||||||
|
#include "repl.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
const u32 VM_RAW_AST = 1;
|
const u32 VM_RAW_AST = 1;
|
||||||
const u32 VM_AST = 1<<1;
|
const u32 VM_AST = 1<<1;
|
||||||
const u32 VM_CODE = 1<<2;
|
const u32 VM_CODE = 1<<2;
|
||||||
const u32 VM_TIME = 1<<3;
|
const u32 VM_TIME = 1<<3;
|
||||||
const u32 VM_EXEC = 1<<4;
|
const u32 VM_EXEC = 1<<4;
|
||||||
const u32 VM_DETAIL = 1<<5;
|
const u32 VM_DETAIL = 1<<5;
|
||||||
const u32 VM_DEBUG = 1<<6;
|
const u32 VM_DEBUG = 1<<6;
|
||||||
const u32 VM_SYMINFO = 1<<7;
|
const u32 VM_SYMINFO = 1<<7;
|
||||||
const u32 VM_PROFILE = 1<<8;
|
const u32 VM_PROFILE = 1<<8;
|
||||||
const u32 VM_PROF_ALL = 1<<9;
|
const u32 VM_PROF_ALL = 1<<9;
|
||||||
|
|
||||||
std::ostream& help(std::ostream& out) {
|
std::ostream& help(std::ostream& out) {
|
||||||
out
|
out
|
||||||
|
@ -53,6 +54,7 @@ std::ostream& help(std::ostream& out) {
|
||||||
<< " --prof | show profiling result, available under debug mode.\n"
|
<< " --prof | show profiling result, available under debug mode.\n"
|
||||||
<< " --prof-all | show profiling result of all files,"
|
<< " --prof-all | show profiling result of all files,"
|
||||||
<< "available under debug mode.\n"
|
<< "available under debug mode.\n"
|
||||||
|
<< " -r, --repl | use repl interpreter(experimental).\n"
|
||||||
<< "file:\n"
|
<< "file:\n"
|
||||||
<< " <filename> | execute file.\n"
|
<< " <filename> | execute file.\n"
|
||||||
<< "argv:\n"
|
<< "argv:\n"
|
||||||
|
@ -129,9 +131,8 @@ void execute(
|
||||||
ld.link(parse, file, cmd&VM_DETAIL).chkerr();
|
ld.link(parse, file, cmd&VM_DETAIL).chkerr();
|
||||||
|
|
||||||
// optimizer does simple optimization on ast
|
// optimizer does simple optimization on ast
|
||||||
auto opt = new optimizer;
|
auto opt = std::unique_ptr<optimizer>(new optimizer);
|
||||||
opt->do_optimization(parse.tree());
|
opt->do_optimization(parse.tree());
|
||||||
delete opt;
|
|
||||||
if (cmd&VM_AST) {
|
if (cmd&VM_AST) {
|
||||||
auto dumper = std::unique_ptr<ast_dumper>(new ast_dumper);
|
auto dumper = std::unique_ptr<ast_dumper>(new ast_dumper);
|
||||||
dumper->dump(parse.tree());
|
dumper->dump(parse.tree());
|
||||||
|
@ -178,6 +179,9 @@ i32 main(i32 argc, const char* argv[]) {
|
||||||
std::clog << help;
|
std::clog << help;
|
||||||
} else if (s=="-v" || s=="--version") {
|
} else if (s=="-v" || s=="--version") {
|
||||||
std::clog << 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]!='-') {
|
} else if (s[0]!='-') {
|
||||||
execute(s, {}, VM_EXEC);
|
execute(s, {}, VM_EXEC);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1144,7 +1144,7 @@ void codegen::ret_gen(return_expr* node) {
|
||||||
gen(op_ret, 0, node->get_location());
|
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_native_function();
|
||||||
init_file_map(import.get_file_list());
|
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
|
// search global symbols first
|
||||||
find_symbol(parse.tree());
|
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
|
// generate main block
|
||||||
block_gen(parse.tree());
|
block_gen(parse.tree());
|
||||||
|
|
|
@ -132,7 +132,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
codegen() = default;
|
codegen() = default;
|
||||||
const error& compile(parse&, linker&, bool repl = false);
|
const error& compile(parse&, linker&);
|
||||||
void print(std::ostream&);
|
void print(std::ostream&);
|
||||||
void symbol_dump(std::ostream&) const;
|
void symbol_dump(std::ostream&) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -31,6 +31,9 @@ var count_bracket = func(line) {
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
var line = readline(">>> ");
|
var line = readline(">>> ");
|
||||||
|
if (!size(line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (line == ".exit" or line == ".quit") {
|
if (line == ".exit" or line == ".quit") {
|
||||||
break;
|
break;
|
||||||
} elsif (line == ".help") {
|
} elsif (line == ".help") {
|
||||||
|
|
Loading…
Reference in New Issue