diff --git a/CMakeLists.txt b/CMakeLists.txt index a2a6f13..ef2d704 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/makefile b/makefile index 456f98d..1f94936 100644 --- a/makefile +++ b/makefile @@ -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 . diff --git a/src/main.cpp b/src/main.cpp index 6867690..c1fb578 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,21 +11,22 @@ #include "nasal_codegen.h" #include "nasal_vm.h" #include "nasal_dbg.h" +#include "repl.h" #include #include #include -const u32 VM_RAW_AST = 1; -const u32 VM_AST = 1<<1; -const u32 VM_CODE = 1<<2; -const u32 VM_TIME = 1<<3; -const u32 VM_EXEC = 1<<4; -const u32 VM_DETAIL = 1<<5; -const u32 VM_DEBUG = 1<<6; -const u32 VM_SYMINFO = 1<<7; -const u32 VM_PROFILE = 1<<8; -const u32 VM_PROF_ALL = 1<<9; +const u32 VM_RAW_AST = 1; +const u32 VM_AST = 1<<1; +const u32 VM_CODE = 1<<2; +const u32 VM_TIME = 1<<3; +const u32 VM_EXEC = 1<<4; +const u32 VM_DETAIL = 1<<5; +const u32 VM_DEBUG = 1<<6; +const u32 VM_SYMINFO = 1<<7; +const u32 VM_PROFILE = 1<<8; +const u32 VM_PROF_ALL = 1<<9; std::ostream& help(std::ostream& out) { out @@ -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" << " | 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(new optimizer); opt->do_optimization(parse.tree()); - delete opt; if (cmd&VM_AST) { auto dumper = std::unique_ptr(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(new repl::repl); + repl_module->execute(); } else if (s[0]!='-') { execute(s, {}, VM_EXEC); } else { diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 28477c8..9a9fc1a 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -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()); diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 141f75b..121befc 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -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; }; diff --git a/src/repl.cpp b/src/repl.cpp new file mode 100644 index 0000000..3be8f19 --- /dev/null +++ b/src/repl.cpp @@ -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(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(new lexer); + auto nasal_parser = std::unique_ptr(new parse); + auto nasal_linker = std::unique_ptr(new linker); + auto nasal_opt = std::unique_ptr(new optimizer); + auto nasal_codegen = std::unique_ptr(new codegen); + auto nasal_runtime = std::unique_ptr(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"; + } +} + +} \ No newline at end of file diff --git a/src/repl.h b/src/repl.h new file mode 100644 index 0000000..3a2ef8a --- /dev/null +++ b/src/repl.h @@ -0,0 +1,28 @@ +#pragma once + +#include "nasal.h" + +#include +#include +#include +#include +#include + +namespace repl { + +class repl { +private: + std::vector source; + +private: + std::string readline(std::string); + bool check_need_more_input(); + void update_temp_file(); + void help(); + bool run(); + +public: + void execute(); +}; + +} \ No newline at end of file diff --git a/tools/repl.nas b/tools/repl.nas index 12d388e..74a3cc2 100644 --- a/tools/repl.nas +++ b/tools/repl.nas @@ -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") {