Merge pull request #44 from ValKmjolnir/develop

 support `??` and `?.` operators & fix utf8 output on MSVC
This commit is contained in:
ValK 2024-06-06 00:03:56 +08:00 committed by GitHub
commit 5aa99f396b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 656 additions and 307 deletions

View File

@ -10,6 +10,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall") set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall")
add_compile_options(-fPIC) add_compile_options(-fPIC)
# MSVC needs this command option to really enable utf-8 output
if(MSVC)
add_compile_options(/utf-8)
endif()
# generate release executables # generate release executables
set(CMAKE_BUILD_TYPE "Release") set(CMAKE_BUILD_TYPE "Release")

View File

@ -112,7 +112,12 @@ build/nasal_type.o:\
src/nasal_type.h src/nasal_type.cpp | build src/nasal_type.h src/nasal_type.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_type.cpp -o build/nasal_type.o $(CXX) $(CXXFLAGS) src/nasal_type.cpp -o build/nasal_type.o
build/nasal_gc.o: src/nasal.h src/nasal_type.h src/nasal_gc.h src/nasal_gc.cpp | build build/nasal_gc.o:\
src/nasal.h\
src/util/util.h\
src/nasal_type.h\
src/nasal_gc.h\
src/nasal_gc.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_gc.cpp -o build/nasal_gc.o $(CXX) $(CXXFLAGS) src/nasal_gc.cpp -o build/nasal_gc.o
build/nasal_import.o: \ build/nasal_import.o: \

View File

@ -185,6 +185,7 @@ bool ast_dumper::visit_binary_operator(binary_operator* node) {
case binary_operator::binary_type::leq: std::cout << "<="; break; case binary_operator::binary_type::leq: std::cout << "<="; break;
case binary_operator::binary_type::condition_and: std::cout << "and"; break; case binary_operator::binary_type::condition_and: std::cout << "and"; break;
case binary_operator::binary_type::condition_or: std::cout << "or"; break; case binary_operator::binary_type::condition_or: std::cout << "or"; break;
case binary_operator::binary_type::null_chain: std::cout << "??"; break;
} }
std::cout << "\"" << format_location(node); std::cout << "\"" << format_location(node);
push_indent(); push_indent();
@ -241,6 +242,13 @@ bool ast_dumper::visit_call_hash(call_hash* node) {
return true; return true;
} }
bool ast_dumper::visit_null_access(null_access* node) {
dump_indent();
std::cout << "null_access " << node->get_field();
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_call_vector(call_vector* node) { bool ast_dumper::visit_call_vector(call_vector* node) {
dump_indent(); dump_indent();
std::cout << "call_vector"; std::cout << "call_vector";

View File

@ -45,7 +45,7 @@ private:
std::string format_location(expr* node) { std::string format_location(expr* node) {
std::stringstream ss; std::stringstream ss;
ss << " ["; ss << " [";
node->get_location().dump_begin(ss); node->get_location().dump_begin(ss);
ss << "]\n"; ss << "]\n";
return ss.str(); return ss.str();
@ -70,6 +70,7 @@ public:
bool visit_unary_operator(unary_operator*) override; bool visit_unary_operator(unary_operator*) override;
bool visit_call_expr(call_expr*) override; bool visit_call_expr(call_expr*) override;
bool visit_call_hash(call_hash*) override; bool visit_call_hash(call_hash*) override;
bool visit_null_access(null_access*) override;
bool visit_call_vector(call_vector*) override; bool visit_call_vector(call_vector*) override;
bool visit_call_function(call_function*) override; bool visit_call_function(call_function*) override;
bool visit_slice_vector(slice_vector*) override; bool visit_slice_vector(slice_vector*) override;
@ -90,10 +91,10 @@ public:
public: public:
void dump(code_block* root) { void dump(code_block* root) {
util::windows_code_page_manager wcpm; util::windows_code_page_manager wm;
wcpm.set_utf8_output(); wm.set_utf8_output();
root->accept(this); root->accept(this);
wcpm.restore_code_page(); wm.restore_code_page();
} }
}; };

View File

@ -116,6 +116,10 @@ bool ast_visitor::visit_call_hash(call_hash* node) {
return true; return true;
} }
bool ast_visitor::visit_null_access(null_access* node) {
return true;
}
bool ast_visitor::visit_call_vector(call_vector* node) { bool ast_visitor::visit_call_vector(call_vector* node) {
for(auto i : node->get_slices()) { for(auto i : node->get_slices()) {
i->accept(this); i->accept(this);

View File

@ -26,6 +26,7 @@ public:
virtual bool visit_unary_operator(unary_operator*); virtual bool visit_unary_operator(unary_operator*);
virtual bool visit_call_expr(call_expr*); virtual bool visit_call_expr(call_expr*);
virtual bool visit_call_hash(call_hash*); virtual bool visit_call_hash(call_hash*);
virtual bool visit_null_access(null_access*);
virtual bool visit_call_vector(call_vector*); virtual bool visit_call_vector(call_vector*);
virtual bool visit_call_function(call_function*); virtual bool visit_call_function(call_function*);
virtual bool visit_slice_vector(slice_vector*); virtual bool visit_slice_vector(slice_vector*);

View File

@ -23,4 +23,40 @@ cli_config parse(const std::vector<std::string>& args) {
return result; return result;
} }
std::ostream& help(std::ostream& out) {
out
<< "\n"
<< " ,--#-,\n"
<< "<3 / \\____\\ <3\n"
<< " |_|__A_|\n"
<< "\nnasal <option>\n"
<< "option:\n"
<< " -h, --help | get help.\n"
<< " -v, --version | get version.\n"
<< " -r, --repl | use repl interpreter.\n"
<< "\nnasal [option] <file> [argv]\n"
<< "option:\n"
<< " -a, --ast | view ast after link/optimize process.\n"
<< " --raw-ast | view ast without after-processing.\n"
<< " -c, --code | view generated bytecode.\n"
<< " -s, --symbol | show analysed symbol info.\n"
<< " -e, --exec | execute directly.\n"
<< " -t, --time | show execute time.\n"
<< " -d, --detail | get detail info.\n"
<< " -f, --ref-file | get referenced files.\n"
<< " -dbg, --debug | debug mode.\n"
<< " --prof | show profiling result, "
<< "available under debug mode.\n"
<< " --prof-all | show profiling result of all files, "
<< "available under debug mode.\n"
<< " --limit | use limited execution mode "
<< "(readonly api enabled).\n"
<< "file:\n"
<< " <filename> | execute file.\n"
<< "argv:\n"
<< " <args> | cmd arguments used in program.\n"
<< "\n";
return out;
}
} }

View File

@ -5,6 +5,7 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include <iostream>
namespace nasal::cli { namespace nasal::cli {
@ -67,4 +68,6 @@ const std::unordered_map<std::string, option> cli_options = {
cli_config parse(const std::vector<std::string>&); cli_config parse(const std::vector<std::string>&);
std::ostream& help(std::ostream&);
} }

View File

@ -18,45 +18,9 @@
#include "repl/repl.h" #include "repl/repl.h"
#include "cli/cli.h" #include "cli/cli.h"
#include <unordered_map>
#include <thread> #include <thread>
#include <cstdlib> #include <cstdlib>
std::ostream& help(std::ostream& out) {
out
<< "\n"
<< " ,--#-,\n"
<< "<3 / \\____\\ <3\n"
<< " |_|__A_|\n"
<< "\nnasal <option>\n"
<< "option:\n"
<< " -h, --help | get help.\n"
<< " -v, --version | get version.\n"
<< " -r, --repl | use repl interpreter.\n"
<< "\nnasal [option] <file> [argv]\n"
<< "option:\n"
<< " -a, --ast | view ast after link/optimize process.\n"
<< " --raw-ast | view ast without after-processing.\n"
<< " -c, --code | view generated bytecode.\n"
<< " -s, --symbol | show analysed symbol info.\n"
<< " -e, --exec | execute directly.\n"
<< " -t, --time | show execute time.\n"
<< " -d, --detail | get detail info.\n"
<< " -f, --ref-file | get referenced files.\n"
<< " -dbg, --debug | debug mode.\n"
<< " --prof | show profiling result, available in debug mode.\n"
<< " --prof-all | show profiling result of all files, "
<< "available under debug mode.\n"
<< " --limit | use limited execution mode "
<< "(readonly api enabled).\n"
<< "file:\n"
<< " <filename> | execute file.\n"
<< "argv:\n"
<< " <args> | cmd arguments used in program.\n"
<< "\n";
return out;
}
std::ostream& logo(std::ostream& out) { std::ostream& logo(std::ostream& out) {
out out
<< "\n" << "\n"
@ -67,7 +31,8 @@ std::ostream& logo(std::ostream& out) {
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n" << " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
<< "\n" << "\n"
<< "ver : " << __nasver__ << "ver : " << __nasver__
<< " " << nasal::util::get_platform() << " " << nasal::util::get_arch() << " " << nasal::util::get_platform()
<< " " << nasal::util::get_arch()
<< " (" << __DATE__ << " " << __TIME__ << ")\n" << " (" << __DATE__ << " " << __TIME__ << ")\n"
<< "std : c++ " << __cplusplus << "\n" << "std : c++ " << __cplusplus << "\n"
<< "core : " << std::thread::hardware_concurrency() << " core(s)\n" << "core : " << std::thread::hardware_concurrency() << " core(s)\n"
@ -75,9 +40,9 @@ std::ostream& logo(std::ostream& out) {
<< "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n" << "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n" << "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
<< "\n" << "\n"
<< "presented by fgprc members\n" << "presented by fgprc members:\n"
<< " - http://fgprc.org\n" << " - http://fgprc.org\n"
<< " - http://fgprc.org.cn\n" << " - http://fgprc.org.cn\n"
<< "\n" << "\n"
<< "input <nasal -h> to get help .\n\n"; << "input <nasal -h> to get help .\n\n";
return out; return out;
@ -96,7 +61,8 @@ std::ostream& version(std::ostream& out) {
} }
out << "nasal version " << __nasver__; out << "nasal version " << __nasver__;
out << " " << nasal::util::get_platform() << " " << nasal::util::get_arch(); out << " " << nasal::util::get_platform();
out << " " << nasal::util::get_arch();
out << " (" << __DATE__ << " " << __TIME__ << ")\n"; out << " (" << __DATE__ << " " << __TIME__ << ")\n";
return out; return out;
} }
@ -195,7 +161,7 @@ i32 main(i32 argc, const char* argv[]) {
// run directly or show help // run directly or show help
if (argc==2) { if (argc==2) {
if (config.has(nasal::cli::option::cli_help)) { if (config.has(nasal::cli::option::cli_help)) {
std::clog << help; std::clog << nasal::cli::help;
} else if (config.has(nasal::cli::option::cli_version)) { } else if (config.has(nasal::cli::option::cli_version)) {
std::clog << version; std::clog << version;
} else if (config.has(nasal::cli::option::cli_repl_mode)) { } else if (config.has(nasal::cli::option::cli_repl_mode)) {

View File

@ -173,6 +173,10 @@ void call_hash::accept(ast_visitor* visitor) {
visitor->visit_call_hash(this); visitor->visit_call_hash(this);
} }
void null_access::accept(ast_visitor* visitor) {
visitor->visit_null_access(this);
}
call_vector::~call_vector() { call_vector::~call_vector() {
for(auto i : calls) { for(auto i : calls) {
delete i; delete i;

View File

@ -23,6 +23,7 @@ enum class expr_type {
ast_pair, // pair of key and value in hashmap ast_pair, // pair of key and value in hashmap
ast_call, // mark a sub-tree of calling an identifier ast_call, // mark a sub-tree of calling an identifier
ast_callh, // id.name ast_callh, // id.name
ast_null_access, // id?.name
ast_callv, // id[index] ast_callv, // id[index]
ast_callf, // id() ast_callf, // id()
ast_subvec, // id[index:index] ast_subvec, // id[index:index]
@ -302,7 +303,8 @@ public:
bitwise_xor, bitwise_xor,
bitwise_and, bitwise_and,
condition_and, condition_and,
condition_or condition_or,
null_chain
}; };
private: private:
@ -389,6 +391,19 @@ public:
void accept(ast_visitor*) override; void accept(ast_visitor*) override;
}; };
class null_access: public call {
private:
std::string field;
public:
null_access(const span& location, const std::string& name):
call(location, expr_type::ast_null_access),
field(name) {}
~null_access() override = default;
const std::string& get_field() const {return field;}
void accept(ast_visitor*) override;
};
class call_vector: public call { class call_vector: public call {
private: private:
std::vector<slice_vector*> calls; std::vector<slice_vector*> calls;

View File

@ -339,6 +339,8 @@ void codegen::call_gen(call_expr* node) {
call_vector_gen(reinterpret_cast<call_vector*>(i)); break; call_vector_gen(reinterpret_cast<call_vector*>(i)); break;
case expr_type::ast_callf: case expr_type::ast_callf:
call_func_gen(reinterpret_cast<call_function*>(i)); break; call_func_gen(reinterpret_cast<call_function*>(i)); break;
case expr_type::ast_null_access:
null_access_gen(reinterpret_cast<null_access*>(i)); break;
default: break; default: break;
} }
} }
@ -382,6 +384,24 @@ void codegen::call_hash_gen(call_hash* node) {
emit(op_callh, const_string_map.at(node->get_field()), node->get_location()); emit(op_callh, const_string_map.at(node->get_field()), node->get_location());
} }
void codegen::null_access_gen(null_access* node) {
regist_string(node->get_field());
emit(op_dup, 0, node->get_location());
emit(op_pnil, 0, node->get_location());
emit(op_eq, 0, node->get_location());
const auto jmp_false_point = code.size();
emit(op_jf, 0, node->get_location());
const auto jmp_direct_point = code.size();
emit(op_jmp, 0, node->get_location());
code[jmp_false_point].num = code.size();
emit(op_callh, const_string_map.at(node->get_field()), node->get_location());
code[jmp_direct_point].num = code.size();
}
void codegen::call_vector_gen(call_vector* node) { void codegen::call_vector_gen(call_vector* node) {
// maybe this place can use callv-const if ast's first child is ast_num // maybe this place can use callv-const if ast's first child is ast_num
if (node->get_slices().size()==1 && if (node->get_slices().size()==1 &&
@ -455,6 +475,8 @@ void codegen::mcall(expr* node) {
call_vector_gen(reinterpret_cast<call_vector*>(tmp)); break; call_vector_gen(reinterpret_cast<call_vector*>(tmp)); break;
case expr_type::ast_callf: case expr_type::ast_callf:
call_func_gen(reinterpret_cast<call_function*>(tmp)); break; call_func_gen(reinterpret_cast<call_function*>(tmp)); break;
case expr_type::ast_null_access:
null_access_gen(reinterpret_cast<null_access*>(tmp)); break;
default: break; default: break;
} }
} }
@ -467,6 +489,8 @@ void codegen::mcall(expr* node) {
mcall_vec(reinterpret_cast<call_vector*>(tmp)); break; mcall_vec(reinterpret_cast<call_vector*>(tmp)); break;
case expr_type::ast_callf: case expr_type::ast_callf:
die("bad left-value: function call", tmp->get_location()); break; die("bad left-value: function call", tmp->get_location()); break;
case expr_type::ast_null_access:
die("bad left-value: null access test", tmp->get_location()); break;
default: default:
die("bad left-value: unknown call", tmp->get_location()); break; die("bad left-value: unknown call", tmp->get_location()); break;
} }
@ -1059,6 +1083,9 @@ void codegen::binary_gen(binary_operator* node) {
calc_gen(node->get_right()); calc_gen(node->get_right());
emit(op_btand, 0, node->get_location()); emit(op_btand, 0, node->get_location());
return; return;
case binary_operator::binary_type::null_chain:
null_chain_gen(node);
return;
default: break; default: break;
} }
switch(node->get_operator_type()) { switch(node->get_operator_type()) {
@ -1174,6 +1201,23 @@ void codegen::binary_gen(binary_operator* node) {
} }
} }
void codegen::null_chain_gen(binary_operator* node) {
calc_gen(node->get_left());
emit(op_pnil, 0, node->get_location());
emit(op_eq, 0, node->get_location());
const auto jmp_false_point = code.size();
emit(op_jf, 0, node->get_location());
calc_gen(node->get_right());
const auto jmp_direct_point = code.size();
emit(op_jmp, 0, node->get_location());
code[jmp_false_point].num = code.size();
emit(op_pop, 0, node->get_location());
code[jmp_direct_point].num = code.size();
}
void codegen::trino_gen(ternary_operator* node) { void codegen::trino_gen(ternary_operator* node) {
calc_gen(node->get_condition()); calc_gen(node->get_condition());
usize label_jump_false = code.size(); usize label_jump_false = code.size();

View File

@ -123,6 +123,7 @@ private:
void call_gen(call_expr*); void call_gen(call_expr*);
void call_identifier(identifier*); void call_identifier(identifier*);
void call_hash_gen(call_hash*); void call_hash_gen(call_hash*);
void null_access_gen(null_access*);
void call_vector_gen(call_vector*); void call_vector_gen(call_vector*);
void call_func_gen(call_function*); void call_func_gen(call_function*);
void mcall(expr*); void mcall(expr*);
@ -148,6 +149,7 @@ private:
void and_gen(binary_operator*); void and_gen(binary_operator*);
void unary_gen(unary_operator*); void unary_gen(unary_operator*);
void binary_gen(binary_operator*); void binary_gen(binary_operator*);
void null_chain_gen(binary_operator*);
void trino_gen(ternary_operator*); void trino_gen(ternary_operator*);
void calc_gen(expr*); void calc_gen(expr*);
void repl_mode_info_output_gen(expr*); void repl_mode_info_output_gen(expr*);

View File

@ -46,8 +46,9 @@ void operand_line_counter::dump_operand_count() const {
if (!rate) { if (!rate) {
break; break;
} }
std::clog << " " << oprand_name_table[i.first] << " : "; std::clog << " ";
std::clog << i.second << " (" << rate << "%)\n"; std::clog << operand_name_table.at(static_cast<op_code_type>(i.first));
std::clog << " : " << i.second << " (" << rate << "%)\n";
} }
std::clog << " total : " << total << '\n'; std::clog << " total : " << total << '\n';
} }

View File

@ -40,55 +40,6 @@ public:
}; };
class dbg: public vm { class dbg: public vm {
private:
typedef void (dbg::*nasal_vm_func)();
const nasal_vm_func operand_function[op_ret + 1] = {
nullptr, &dbg::o_repl,
&dbg::o_intl, &dbg::o_loadg,
&dbg::o_loadl, &dbg::o_loadu,
&dbg::o_pnum, &dbg::o_pnil,
&dbg::o_pstr, &dbg::o_newv,
&dbg::o_newh, &dbg::o_newf,
&dbg::o_happ, &dbg::o_para,
&dbg::o_deft, &dbg::o_dyn,
&dbg::o_lnot, &dbg::o_usub,
&dbg::o_bnot, &dbg::o_btor,
&dbg::o_btxor, &dbg::o_btand,
&dbg::o_add, &dbg::o_sub,
&dbg::o_mul, &dbg::o_div,
&dbg::o_lnk, &dbg::o_addc,
&dbg::o_subc, &dbg::o_mulc,
&dbg::o_divc, &dbg::o_lnkc,
&dbg::o_addeq, &dbg::o_subeq,
&dbg::o_muleq, &dbg::o_diveq,
&dbg::o_lnkeq, &dbg::o_bandeq,
&dbg::o_boreq, &dbg::o_bxoreq,
&dbg::o_addeqc, &dbg::o_subeqc,
&dbg::o_muleqc, &dbg::o_diveqc,
&dbg::o_lnkeqc, &dbg::o_addecp,
&dbg::o_subecp, &dbg::o_mulecp,
&dbg::o_divecp, &dbg::o_lnkecp,
&dbg::o_meq, &dbg::o_eq,
&dbg::o_neq, &dbg::o_less,
&dbg::o_leq, &dbg::o_grt,
&dbg::o_geq, &dbg::o_lessc,
&dbg::o_leqc, &dbg::o_grtc,
&dbg::o_geqc, &dbg::o_pop,
&dbg::o_jmp, &dbg::o_jt,
&dbg::o_jf, &dbg::o_cnt,
&dbg::o_findex, &dbg::o_feach,
&dbg::o_callg, &dbg::o_calll,
&dbg::o_upval, &dbg::o_callv,
&dbg::o_callvi, &dbg::o_callh,
&dbg::o_callfv, &dbg::o_callfh,
&dbg::o_callb, &dbg::o_slcbeg,
&dbg::o_slcend, &dbg::o_slc,
&dbg::o_slc2, &dbg::o_mcallg,
&dbg::o_mcalll, &dbg::o_mupval,
&dbg::o_mcallv, &dbg::o_mcallh,
&dbg::o_ret
};
private: private:
enum class cmd_kind { enum class cmd_kind {
cmd_error, cmd_error,

View File

@ -1,4 +1,5 @@
#include "nasal_gc.h" #include "nasal_gc.h"
#include "util/util.h"
namespace nasal { namespace nasal {
@ -258,15 +259,27 @@ void gc::clear() {
} }
void gc::info() const { void gc::info() const {
util::windows_code_page_manager wm;
wm.set_utf8_output();
using std::left; using std::left;
using std::setw; using std::setw;
using std::setfill; using std::setfill;
using std::setprecision;
const char* used_table_name[] = { const char* used_table_name[] = {
"object type", "gc count", "alloc count", "memory size", "object type",
"detail", "time spend", "gc time", "avg time", "max gc", "gc count",
"max mark", "max sweep", nullptr "alloc count",
"memory size",
"detail",
"time spend",
"gc time",
"avg time",
"max gc",
"max mark",
"max sweep",
nullptr
}; };
const char* name[] = { const char* name[] = {
"string", "string",
@ -297,21 +310,33 @@ void gc::info() const {
len = std::to_string(size[i]).length(); len = std::to_string(size[i]).length();
indent = indent<len? len:indent; indent = indent<len? len:indent;
} }
auto indent_string = std::string("--"); auto indent_string = std::string("──");
for(usize i = 0; i<indent; ++i) { for(usize i = 0; i<indent; ++i) {
indent_string += "-"; indent_string += "";
} }
const auto last_line = "+" + indent_string + "+" + const auto first_line = "" + indent_string + "" +
indent_string + "-" + indent_string + "-" + indent_string + "+"; indent_string + "" +
indent_string = indent_string + "+" + indent_string + "" +
indent_string + "+" + indent_string + "+" + indent_string; indent_string + "";
const auto mid_line = "" + indent_string + "" +
indent_string + "" +
indent_string + "" +
indent_string + "";
const auto another_mid_line = "" + indent_string + "" +
indent_string + "" +
indent_string + "" +
indent_string + "";
const auto last_line = "" + indent_string + "" +
indent_string + "" +
indent_string + "" +
indent_string + "";
std::clog << "\n+" << indent_string << "+\n"; std::clog << "\n" << first_line << "\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "object type"; std::clog << " " << left << setw(indent) << setfill(' ') << "object type";
std::clog << " | " << left << setw(indent) << setfill(' ') << "gc count"; std::clog << " " << left << setw(indent) << setfill(' ') << "gc count";
std::clog << " | " << left << setw(indent) << setfill(' ') << "alloc count"; std::clog << " " << left << setw(indent) << setfill(' ') << "alloc count";
std::clog << " | " << left << setw(indent) << setfill(' ') << "memory size"; std::clog << " " << left << setw(indent) << setfill(' ') << "memory size";
std::clog << " |\n+" << indent_string << "+\n"; std::clog << " \n" << mid_line << "\n";
double total = 0; double total = 0;
for(u8 i = 0; i<gc_type_size; ++i) { for(u8 i = 0; i<gc_type_size; ++i) {
@ -319,46 +344,54 @@ void gc::info() const {
continue; continue;
} }
total += static_cast<f64>(gcnt[i]); total += static_cast<f64>(gcnt[i]);
std::clog << "| " << left << setw(indent) << setfill(' ') << name[i]; std::clog << " " << left << setw(indent) << setfill(' ') << name[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << gcnt[i]; std::clog << " " << left << setw(indent) << setfill(' ') << gcnt[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << acnt[i]; std::clog << " " << left << setw(indent) << setfill(' ') << acnt[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << size[i]; std::clog << " " << left << setw(indent) << setfill(' ') << size[i];
std::clog << " |\n"; std::clog << " \n";
} }
std::clog << "+" << indent_string << "+\n"; std::clog << mid_line << "\n";
auto den = std::chrono::high_resolution_clock::duration::period::den; const auto den = std::chrono::high_resolution_clock::duration::period::den;
std::clog << "| " << left << setw(indent) << setfill(' ') << "detail"; std::clog << " " << left << setw(indent) << setfill(' ') << "detail";
std::clog << " | " << left << setw(indent) << setfill(' ') << "time spend"; std::clog << " " << left << setw(indent) << setfill(' ') << "time spend";
std::clog << " | " << left << setw(indent) << setfill('x') << "x"; std::clog << " " << left << setw(indent) << setfill('x') << "x";
std::clog << " | " << left << setw(indent) << setfill('x') << "x"; std::clog << " " << left << setw(indent) << setfill('x') << "x";
std::clog << " |\n+" << indent_string << "+\n"; std::clog << " \n" << another_mid_line << "\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "gc time"; const auto gc_time = worktime*1.0/den*1000;
std::clog << " | " << setw(indent-3) << std::setprecision(4) << worktime*1.0/den*1000 << " ms"; std::clog << "" << left << setw(indent) << setfill(' ') << "gc time";
std::clog << setw(indent*2+7) << " " << "|\n"; std::clog << "" << setw(indent-3) << setprecision(4) << gc_time << " ms";
std::clog << setw(indent*2+7) << " " << "\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "avg time"; const auto avg_time = worktime*1.0/den*1000/total;
std::clog << " | " << setw(indent-3) << std::setprecision(4) << worktime*1.0/den*1000/total << " ms"; std::clog << "" << left << setw(indent) << setfill(' ') << "avg time";
std::clog << setw(indent*2+7) << " " << "|\n"; std::clog << "" << setw(indent-3) << setprecision(4) << avg_time << " ms";
std::clog << setw(indent*2+7) << " " << "\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "max gc"; const auto max_gc = max_time*1.0/den*1000;
std::clog << " | " << setw(indent-3) << std::setprecision(4) << max_time*1.0/den*1000 << " ms"; std::clog << "" << left << setw(indent) << setfill(' ') << "max gc";
std::clog << setw(indent*2+7) << " " << "|\n"; std::clog << "" << setw(indent-3) << setprecision(4) << max_gc << " ms";
std::clog << setw(indent*2+7) << " " << "\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "max mark"; const auto max_mark = max_mark_time*1.0/den*1000;
std::clog << " | " << setw(indent-3) << std::setprecision(4) << max_mark_time*1.0/den*1000 << " ms"; std::clog << "" << left << setw(indent) << setfill(' ') << "max mark";
std::clog << setw(indent*2+7) << " " << "|\n"; std::clog << "" << setw(indent-3) << setprecision(4) << max_mark << " ms";
std::clog << setw(indent*2+7) << " " << "\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "max sweep"; const auto max_sweep = max_sweep_time*1.0/den*1000;
std::clog << " | " << setw(indent-3) << std::setprecision(4) << max_sweep_time*1.0/den*1000 << " ms"; std::clog << "" << left << setw(indent) << setfill(' ') << "max sweep";
std::clog << setw(indent*2+7) << " " << "|\n"; std::clog << "" << setw(indent-3) << setprecision(4) << max_sweep << " ms";
std::clog << setw(indent*2+7) << " " << "\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "concurrent"; std::clog << "" << left << setw(indent) << setfill(' ') << "concurrent";
std::clog << " | " << setw(indent) << (flag_concurrent_mark_triggered? "true":"false"); std::clog << "" << setw(indent)
std::clog << setw(indent*2+7) << " " << "|\n"; << (flag_concurrent_mark_triggered? "true":"false");
std::clog << setw(indent*2+7) << " " << "\n";
std::clog << last_line << "\n"; std::clog << last_line << "\n";
wm.restore_code_page();
} }
var gc::alloc(const vm_type type) { var gc::alloc(const vm_type type) {

View File

@ -35,12 +35,16 @@ bool lexer::is_str(char c) {
return c=='\'' || c=='\"' || c=='`'; return c=='\'' || c=='\"' || c=='`';
} }
bool lexer::is_quesmark(char c) {
return c=='?';
}
bool lexer::is_single_opr(char c) { bool lexer::is_single_opr(char c) {
return ( return (
c=='(' || c==')' || c=='[' || c==']' || c=='(' || c==')' || c=='[' || c==']' ||
c=='{' || c=='}' || c==',' || c==';' || c=='{' || c=='}' || c==',' || c==';' ||
c==':' || c=='?' || c=='`' || c=='@' || c==':' || c=='`' || c=='@' || c=='%' ||
c=='%' || c=='$' || c=='\\' c=='$' || c=='\\'
); );
} }
@ -103,6 +107,8 @@ void lexer::open(const std::string& file) {
} }
tok lexer::get_type(const std::string& str) { tok lexer::get_type(const std::string& str) {
// search token type from mapper
// if cannot find, just return null
return token_mapper.count(str)? token_mapper.at(str):tok::tk_null; return token_mapper.count(str)? token_mapper.at(str):tok::tk_null;
} }
@ -333,6 +339,24 @@ token lexer::str_gen() {
}; };
} }
token lexer::quesmark_gen() {
u64 begin_line = line;
u64 begin_column = column;
std::string str(1, res[ptr]);
++column;
++ptr;
if (ptr < res.size() && (res[ptr]=='?' || res[ptr]=='.')) {
str += res[ptr];
++column;
++ptr;
}
return {
{begin_line, begin_column, line, column, filename},
get_type(str),
str
};
}
token lexer::single_opr() { token lexer::single_opr() {
u64 begin_line = line; u64 begin_line = line;
u64 begin_column = column; u64 begin_column = column;
@ -398,6 +422,8 @@ const error& lexer::scan(const std::string& file) {
toks.push_back(num_gen()); toks.push_back(num_gen());
} else if (is_str(res[ptr])) { } else if (is_str(res[ptr])) {
toks.push_back(str_gen()); toks.push_back(str_gen());
} else if (is_quesmark(res[ptr])) {
toks.push_back(quesmark_gen());
} else if (is_single_opr(res[ptr])) { } else if (is_single_opr(res[ptr])) {
toks.push_back(single_opr()); toks.push_back(single_opr());
} else if (res[ptr]=='.') { } else if (res[ptr]=='.') {

View File

@ -50,6 +50,8 @@ enum class tok {
tk_dot, // . tk_dot, // .
tk_ellipsis, // ... tk_ellipsis, // ...
tk_quesmark, // ? tk_quesmark, // ?
tk_quesques, // ??
tk_quesdot, // ?.
tk_colon, // : tk_colon, // :
tk_add, // operator + tk_add, // operator +
tk_sub, // operator - tk_sub, // operator -
@ -79,9 +81,10 @@ enum class tok {
}; };
struct token { struct token {
span loc; // location span loc; // location
tok type; // token type tok type; // token type
std::string str; // content std::string str; // content
token() = default; token() = default;
token(const token&) = default; token(const token&) = default;
}; };
@ -94,10 +97,12 @@ private:
std::string filename; std::string filename;
std::string res; std::string res;
private:
error err; error err;
u64 invalid_char; u64 invalid_char;
std::vector<token> toks; std::vector<token> toks;
private:
const std::unordered_map<std::string, tok> token_mapper = { const std::unordered_map<std::string, tok> token_mapper = {
{"use" , tok::tk_use }, {"use" , tok::tk_use },
{"true" , tok::tk_true }, {"true" , tok::tk_true },
@ -128,6 +133,8 @@ private:
{"." , tok::tk_dot }, {"." , tok::tk_dot },
{"..." , tok::tk_ellipsis}, {"..." , tok::tk_ellipsis},
{"?" , tok::tk_quesmark}, {"?" , tok::tk_quesmark},
{"??" , tok::tk_quesques},
{"?." , tok::tk_quesdot },
{":" , tok::tk_colon }, {":" , tok::tk_colon },
{"+" , tok::tk_add }, {"+" , tok::tk_add },
{"-" , tok::tk_sub }, {"-" , tok::tk_sub },
@ -155,6 +162,7 @@ private:
{">=" , tok::tk_geq } {">=" , tok::tk_geq }
}; };
private:
tok get_type(const std::string&); tok get_type(const std::string&);
bool skip(char); bool skip(char);
bool is_id(char); bool is_id(char);
@ -162,6 +170,7 @@ private:
bool is_oct(char); bool is_oct(char);
bool is_dec(char); bool is_dec(char);
bool is_str(char); bool is_str(char);
bool is_quesmark(char);
bool is_single_opr(char); bool is_single_opr(char);
bool is_calc_opr(char); bool is_calc_opr(char);
@ -173,14 +182,17 @@ private:
token id_gen(); token id_gen();
token num_gen(); token num_gen();
token str_gen(); token str_gen();
token quesmark_gen();
token single_opr(); token single_opr();
token dots(); token dots();
token calc_opr(); token calc_opr();
public: public:
lexer(): line(1), column(0), ptr(0), lexer(): line(1), column(0), ptr(0),
filename(""), res(""), invalid_char(0) {} filename(""), res(""),
invalid_char(0) {}
const error& scan(const std::string&); const error& scan(const std::string&);
const std::vector<token>& result() const {return toks;} const auto& result() const {return toks;}
}; };
} }

View File

@ -3,31 +3,6 @@
namespace nasal { namespace nasal {
const char* oprand_name_table[] = {
"exit ", "repl ", "intl ", "loadg ",
"loadl ", "loadu ", "pnum ", "pnil ",
"pstr ", "newv ", "newh ", "newf ",
"happ ", "para ", "def ", "dyn ",
"lnot ", "usub ", "bitnot", "bitor ",
"bitxor", "bitand", "add ", "sub ",
"mult ", "div ", "lnk ", "addc ",
"subc ", "multc ", "divc ", "lnkc ",
"addeq ", "subeq ", "muleq ", "diveq ",
"lnkeq ", "bandeq", "boreq ", "bxoreq",
"addeqc", "subeqc", "muleqc", "diveqc",
"lnkeqc", "addecp", "subecp", "mulecp",
"divecp", "lnkecp", "meq ", "eq ",
"neq ", "less ", "leq ", "grt ",
"geq ", "lessc ", "leqc ", "grtc ",
"geqc ", "pop ", "jmp ", "jt ",
"jf ", "cnt ", "findx ", "feach ",
"callg ", "calll ", "upval ", "callv ",
"callvi", "callh ", "callfv", "callfh",
"callb ", "slcbeg", "slcend", "slice ",
"slice2", "mcallg", "mcalll", "mupval",
"mcallv", "mcallh", "ret "
};
void codestream::set(const f64* number_list, void codestream::set(const f64* number_list,
const std::string* string_list, const std::string* string_list,
const nasal_builtin_table* native_table, const nasal_builtin_table* native_table,
@ -58,7 +33,7 @@ void codestream::dump(std::ostream& out) const {
} }
// dump operand name // dump operand name
out << " " << oprand_name_table[op] << " "; out << " " << operand_name_table.at(static_cast<op_code_type>(op)) << " ";
switch(op) { switch(op) {
case op_addeq: case op_addeq:

View File

@ -14,6 +14,7 @@ enum op_code_type: u8 {
op_loadg, // load global value op_loadg, // load global value
op_loadl, // load local value op_loadl, // load local value
op_loadu, // load upvalue op_loadu, // load upvalue
op_dup, // copy value on stack top
op_pnum, // push constant number to the stack op_pnum, // push constant number to the stack
op_pnil, // push constant nil to the stack op_pnil, // push constant nil to the stack
op_pstr, // push constant std::string to the stack op_pstr, // push constant std::string to the stack
@ -97,6 +98,97 @@ enum op_code_type: u8 {
op_ret // return op_ret // return
}; };
static std::unordered_map<op_code_type, std::string> operand_name_table = {
{op_code_type::op_exit, "exit "},
{op_code_type::op_repl, "repl "},
{op_code_type::op_intl, "intl "},
{op_code_type::op_loadg, "loadg "},
{op_code_type::op_loadl, "loadl "},
{op_code_type::op_loadu, "loadu "},
{op_code_type::op_dup, "dup "},
{op_code_type::op_pnum, "pnum "},
{op_code_type::op_pnil, "pnil "},
{op_code_type::op_pstr, "pstr "},
{op_code_type::op_newv, "newv "},
{op_code_type::op_newh, "newh "},
{op_code_type::op_newf, "newf "},
{op_code_type::op_happ, "happ "},
{op_code_type::op_para, "para "},
{op_code_type::op_deft, "def "},
{op_code_type::op_dyn, "dyn "},
{op_code_type::op_lnot, "lnot "},
{op_code_type::op_usub, "usub "},
{op_code_type::op_bnot, "bitnot"},
{op_code_type::op_btor, "bitor "},
{op_code_type::op_btxor, "bitxor"},
{op_code_type::op_btand, "bitand"},
{op_code_type::op_add, "add "},
{op_code_type::op_sub, "sub "},
{op_code_type::op_mul, "mult "},
{op_code_type::op_div, "div "},
{op_code_type::op_lnk, "lnk "},
{op_code_type::op_addc, "addc "},
{op_code_type::op_subc, "subc "},
{op_code_type::op_mulc, "multc "},
{op_code_type::op_divc, "divc "},
{op_code_type::op_lnkc, "lnkc "},
{op_code_type::op_addeq, "addeq "},
{op_code_type::op_subeq, "subeq "},
{op_code_type::op_muleq, "muleq "},
{op_code_type::op_diveq, "diveq "},
{op_code_type::op_lnkeq, "lnkeq "},
{op_code_type::op_btandeq, "bandeq"},
{op_code_type::op_btoreq, "boreq "},
{op_code_type::op_btxoreq, "bxoreq"},
{op_code_type::op_addeqc, "addeqc"},
{op_code_type::op_subeqc, "subeqc"},
{op_code_type::op_muleqc, "muleqc"},
{op_code_type::op_diveqc, "diveqc"},
{op_code_type::op_lnkeqc, "lnkeqc"},
{op_code_type::op_addecp, "addecp"},
{op_code_type::op_subecp, "subecp"},
{op_code_type::op_mulecp, "mulecp"},
{op_code_type::op_divecp, "divecp"},
{op_code_type::op_lnkecp, "lnkecp"},
{op_code_type::op_meq, "meq "},
{op_code_type::op_eq, "eq "},
{op_code_type::op_neq, "neq "},
{op_code_type::op_less, "less "},
{op_code_type::op_leq, "leq "},
{op_code_type::op_grt, "grt "},
{op_code_type::op_geq, "geq "},
{op_code_type::op_lessc, "lessc "},
{op_code_type::op_leqc, "leqc "},
{op_code_type::op_grtc, "grtc "},
{op_code_type::op_geqc, "geqc "},
{op_code_type::op_pop, "pop "},
{op_code_type::op_jmp, "jmp "},
{op_code_type::op_jt, "jt "},
{op_code_type::op_jf, "jf "},
{op_code_type::op_cnt, "cnt "},
{op_code_type::op_findex, "findx "},
{op_code_type::op_feach, "feach "},
{op_code_type::op_callg, "callg "},
{op_code_type::op_calll, "calll "},
{op_code_type::op_upval, "upval "},
{op_code_type::op_callv, "callv "},
{op_code_type::op_callvi, "callvi"},
{op_code_type::op_callh, "callh "},
{op_code_type::op_callfv, "callfv"},
{op_code_type::op_callfh, "callfh"},
{op_code_type::op_callb, "callb "},
{op_code_type::op_slcbeg, "slcbeg"},
{op_code_type::op_slcend, "slcend"},
{op_code_type::op_slc, "slice "},
{op_code_type::op_slc2, "slice2"},
{op_code_type::op_mcallg, "mcallg"},
{op_code_type::op_mcalll, "mcalll"},
{op_code_type::op_mupval, "mupval"},
{op_code_type::op_mcallv, "mcallv"},
{op_code_type::op_mcallh, "mcallh"},
{op_code_type::op_ret, "ret "}
};
struct opcode { struct opcode {
u8 op; // opcode u8 op; // opcode
u16 fidx; // source code file index u16 fidx; // source code file index
@ -127,6 +219,4 @@ public:
std::ostream& operator<<(std::ostream&, const codestream&); std::ostream& operator<<(std::ostream&, const codestream&);
extern const char* oprand_name_table[];
} }

View File

@ -82,7 +82,11 @@ void parse::match(tok type, const char* info) {
case tok::tk_num: die(thisspan, "expected number"); break; case tok::tk_num: die(thisspan, "expected number"); break;
case tok::tk_str: die(thisspan, "expected string"); break; case tok::tk_str: die(thisspan, "expected string"); break;
case tok::tk_id: die(thisspan, "expected identifier"); break; case tok::tk_id: die(thisspan, "expected identifier"); break;
default: die(thisspan, "expected \""+tokname.at(type)+"\""); break; default:
die(thisspan,
"expected \"" + token_name_mapper.at(type)+"\""
);
break;
} }
return; return;
} }
@ -94,7 +98,8 @@ bool parse::lookahead(tok type) {
} }
bool parse::is_call(tok type) { bool parse::is_call(tok type) {
return type==tok::tk_lcurve || type==tok::tk_lbracket || type==tok::tk_dot; return type==tok::tk_lcurve || type==tok::tk_lbracket ||
type==tok::tk_dot || type==tok::tk_quesdot;
} }
bool parse::check_comma(const tok* panic_set) { bool parse::check_comma(const tok* panic_set) {
@ -564,7 +569,7 @@ expr* parse::and_expr() {
} }
expr* parse::cmp_expr() { expr* parse::cmp_expr() {
auto node = additive_expr(); auto node = null_chain_expr();
while(tok::tk_cmpeq<=toks[ptr].type && toks[ptr].type<=tok::tk_geq) { while(tok::tk_cmpeq<=toks[ptr].type && toks[ptr].type<=tok::tk_geq) {
auto tmp = new binary_operator(toks[ptr].loc); auto tmp = new binary_operator(toks[ptr].loc);
switch(toks[ptr].type) { switch(toks[ptr].type) {
@ -578,6 +583,21 @@ expr* parse::cmp_expr() {
} }
tmp->set_left(node); tmp->set_left(node);
match(toks[ptr].type); match(toks[ptr].type);
tmp->set_right(null_chain_expr());
update_location(tmp);
node = tmp;
}
update_location(node);
return node;
}
expr* parse::null_chain_expr() {
auto node = additive_expr();
while(lookahead(tok::tk_quesques)) {
auto tmp = new binary_operator(toks[ptr].loc);
tmp->set_operator_type(binary_operator::binary_type::null_chain);
tmp->set_left(node);
match(tok::tk_quesques);
tmp->set_right(additive_expr()); tmp->set_right(additive_expr());
update_location(tmp); update_location(tmp);
node = tmp; node = tmp;
@ -718,6 +738,7 @@ call* parse::call_scalar() {
case tok::tk_lcurve: return callf(); break; case tok::tk_lcurve: return callf(); break;
case tok::tk_lbracket: return callv(); break; case tok::tk_lbracket: return callv(); break;
case tok::tk_dot: return callh(); break; case tok::tk_dot: return callh(); break;
case tok::tk_quesdot: return null_access_call(); break;
default: break; default: break;
} }
// unreachable // unreachable
@ -733,6 +754,15 @@ call_hash* parse::callh() {
return node; return node;
} }
null_access* parse::null_access_call() {
const auto& begin_loc = toks[ptr].loc;
match(tok::tk_quesdot);
auto node = new null_access(begin_loc, toks[ptr].str);
update_location(node);
match(tok::tk_id, "expected hashmap key"); // get key
return node;
}
call_vector* parse::callv() { call_vector* parse::callv() {
// panic set for this token is not ',' // panic set for this token is not ','
// this is the FIRST set of subvec // this is the FIRST set of subvec

View File

@ -23,7 +23,7 @@ private:
error err; error err;
private: private:
const std::unordered_map<tok, std::string> tokname = { const std::unordered_map<tok, std::string> token_name_mapper = {
{tok::tk_true , "true" }, {tok::tk_true , "true" },
{tok::tk_false , "false" }, {tok::tk_false , "false" },
{tok::tk_use , "use" }, {tok::tk_use , "use" },
@ -53,6 +53,8 @@ private:
{tok::tk_dot , "." }, {tok::tk_dot , "." },
{tok::tk_ellipsis, "..." }, {tok::tk_ellipsis, "..." },
{tok::tk_quesmark, "?" }, {tok::tk_quesmark, "?" },
{tok::tk_quesques, "??" },
{tok::tk_quesdot , "?." },
{tok::tk_colon , ":" }, {tok::tk_colon , ":" },
{tok::tk_add , "+" }, {tok::tk_add , "+" },
{tok::tk_sub , "-" }, {tok::tk_sub , "-" },
@ -117,12 +119,14 @@ private:
expr* or_expr(); expr* or_expr();
expr* and_expr(); expr* and_expr();
expr* cmp_expr(); expr* cmp_expr();
expr* null_chain_expr();
expr* additive_expr(); expr* additive_expr();
expr* multive_expr(); expr* multive_expr();
unary_operator* unary(); unary_operator* unary();
expr* scalar(); expr* scalar();
call* call_scalar(); call* call_scalar();
call_hash* callh(); call_hash* callh();
null_access* null_access_call();
call_vector* callv(); call_vector* callv();
call_function* callf(); call_function* callf();
slice_vector* subvec(); slice_vector* subvec();
@ -153,8 +157,9 @@ public:
} }
public: public:
parse(): ptr(0), in_func_depth(0), in_loop_depth(0), parse(): ptr(0), in_func_depth(0),
toks(nullptr), root(nullptr) {} in_loop_depth(0), toks(nullptr),
root(nullptr) {}
~parse() {delete root;} ~parse() {delete root;}
const error& compile(const lexer&); const error& compile(const lexer&);
static void easter_egg(); static void easter_egg();

View File

@ -429,28 +429,94 @@ void vm::run(const codegen& gen,
#ifndef _MSC_VER #ifndef _MSC_VER
// using labels as values/computed goto // using labels as values/computed goto
const void* oprs[] = { const void* oprs[] = {
&&vmexit, &&repl, &&intl, &&loadg, &&vmexit,
&&loadl, &&loadu, &&pnum, &&pnil, &&repl,
&&pstr, &&newv, &&newh, &&newf, &&intl,
&&happ, &&para, &&deft, &&dyn, &&loadg,
&&lnot, &&usub, &&bnot, &&btor, &&loadl,
&&btxor, &&btand, &&add, &&sub, &&loadu,
&&mul, &&div, &&lnk, &&addc, &&dup,
&&subc, &&mulc, &&divc, &&lnkc, &&pnum,
&&addeq, &&subeq, &&muleq, &&diveq, &&pnil,
&&lnkeq, &&bandeq, &&boreq, &&bxoreq, &&pstr,
&&addeqc, &&subeqc, &&muleqc, &&diveqc, &&newv,
&&lnkeqc, &&addecp, &&subecp, &&mulecp, &&newh,
&&divecp, &&lnkecp, &&meq, &&eq, &&newf,
&&neq, &&less, &&leq, &&grt, &&happ,
&&geq, &&lessc, &&leqc, &&grtc, &&para,
&&geqc, &&pop, &&jmp, &&jt, &&deft,
&&jf, &&cnt, &&findex, &&feach, &&dyn,
&&callg, &&calll, &&upval, &&callv, &&lnot,
&&callvi, &&callh, &&callfv, &&callfh, &&usub,
&&callb, &&slcbeg, &&slcend, &&slc, &&bnot,
&&slc2, &&mcallg, &&mcalll, &&mupval, &&btor,
&&mcallv, &&mcallh, &&ret &&btxor,
&&btand,
&&add,
&&sub,
&&mul,
&&div,
&&lnk,
&&addc,
&&subc,
&&mulc,
&&divc,
&&lnkc,
&&addeq,
&&subeq,
&&muleq,
&&diveq,
&&lnkeq,
&&bandeq,
&&boreq,
&&bxoreq,
&&addeqc,
&&subeqc,
&&muleqc,
&&diveqc,
&&lnkeqc,
&&addecp,
&&subecp,
&&mulecp,
&&divecp,
&&lnkecp,
&&meq,
&&eq,
&&neq,
&&less,
&&leq,
&&grt,
&&geq,
&&lessc,
&&leqc,
&&grtc,
&&geqc,
&&pop,
&&jmp,
&&jt,
&&jf,
&&cnt,
&&findex,
&&feach,
&&callg,
&&calll,
&&upval,
&&callv,
&&callvi,
&&callh,
&&callfv,
&&callfh,
&&callb,
&&slcbeg,
&&slcend,
&&slc,
&&slc2,
&&mcallg,
&&mcalll,
&&mupval,
&&mcallv,
&&mcallh,
&&ret
}; };
std::vector<const void*> code; std::vector<const void*> code;
for(const auto& i : gen.codes()) { for(const auto& i : gen.codes()) {
@ -460,56 +526,9 @@ void vm::run(const codegen& gen,
// goto the first operand // goto the first operand
goto *code[ctx.pc]; goto *code[ctx.pc];
#else #else
typedef void (vm::*nafunc)(); std::vector<nasal_vm_func> code;
const nafunc oprs[] = {
nullptr, &vm::o_repl,
&vm::o_intl, &vm::o_loadg,
&vm::o_loadl, &vm::o_loadu,
&vm::o_pnum, &vm::o_pnil,
&vm::o_pstr, &vm::o_newv,
&vm::o_newh, &vm::o_newf,
&vm::o_happ, &vm::o_para,
&vm::o_deft, &vm::o_dyn,
&vm::o_lnot, &vm::o_usub,
&vm::o_bnot, &vm::o_btor,
&vm::o_btxor, &vm::o_btand,
&vm::o_add, &vm::o_sub,
&vm::o_mul, &vm::o_div,
&vm::o_lnk, &vm::o_addc,
&vm::o_subc, &vm::o_mulc,
&vm::o_divc, &vm::o_lnkc,
&vm::o_addeq, &vm::o_subeq,
&vm::o_muleq, &vm::o_diveq,
&vm::o_lnkeq, &vm::o_bandeq,
&vm::o_boreq, &vm::o_bxoreq,
&vm::o_addeqc, &vm::o_subeqc,
&vm::o_muleqc, &vm::o_diveqc,
&vm::o_lnkeqc, &vm::o_addecp,
&vm::o_subecp, &vm::o_mulecp,
&vm::o_divecp, &vm::o_lnkecp,
&vm::o_meq, &vm::o_eq,
&vm::o_neq, &vm::o_less,
&vm::o_leq, &vm::o_grt,
&vm::o_geq, &vm::o_lessc,
&vm::o_leqc, &vm::o_grtc,
&vm::o_geqc, &vm::o_pop,
&vm::o_jmp, &vm::o_jt,
&vm::o_jf, &vm::o_cnt,
&vm::o_findex, &vm::o_feach,
&vm::o_callg, &vm::o_calll,
&vm::o_upval, &vm::o_callv,
&vm::o_callvi, &vm::o_callh,
&vm::o_callfv, &vm::o_callfh,
&vm::o_callb, &vm::o_slcbeg,
&vm::o_slcend, &vm::o_slc,
&vm::o_slc2, &vm::o_mcallg,
&vm::o_mcalll, &vm::o_mupval,
&vm::o_mcallv, &vm::o_mcallh,
&vm::o_ret
};
std::vector<nafunc> code;
for(const auto& i : gen.codes()) { for(const auto& i : gen.codes()) {
code.push_back(oprs[i.op]); code.push_back(operand_function[i.op]);
imm.push_back(i.num); imm.push_back(i.num);
} }
while(code[ctx.pc]) { while(code[ctx.pc]) {
@ -520,7 +539,7 @@ void vm::run(const codegen& gen,
++ctx.pc; ++ctx.pc;
} }
#endif #endif
// all nasal programs should end here
vmexit: vmexit:
if (verbose) { if (verbose) {
ngc.info(); ngc.info();
@ -551,6 +570,7 @@ intl: exec_nodie(o_intl ); // -0
loadg: exec_nodie(o_loadg ); // -1 loadg: exec_nodie(o_loadg ); // -1
loadl: exec_nodie(o_loadl ); // -1 loadl: exec_nodie(o_loadl ); // -1
loadu: exec_nodie(o_loadu ); // -1 loadu: exec_nodie(o_loadu ); // -1
dup: exec_check(o_dup ); // +1
pnum: exec_check(o_pnum ); // +1 pnum: exec_check(o_pnum ); // +1
pnil: exec_check(o_pnil ); // +1 pnil: exec_check(o_pnil ); // +1
pstr: exec_check(o_pstr ); // +1 pstr: exec_check(o_pstr ); // +1

View File

@ -93,6 +93,7 @@ protected:
inline void o_loadg(); inline void o_loadg();
inline void o_loadl(); inline void o_loadl();
inline void o_loadu(); inline void o_loadu();
inline void o_dup();
inline void o_pnum(); inline void o_pnum();
inline void o_pnil(); inline void o_pnil();
inline void o_pstr(); inline void o_pstr();
@ -175,6 +176,100 @@ protected:
inline void o_mcallh(); inline void o_mcallh();
inline void o_ret(); inline void o_ret();
protected:
// for debugger and MSVC(does not support labels as values)
typedef void (vm::*nasal_vm_func)();
const nasal_vm_func operand_function[op_ret + 1] = {
nullptr,
&vm::o_repl,
&vm::o_intl,
&vm::o_loadg,
&vm::o_loadl,
&vm::o_loadu,
&vm::o_dup,
&vm::o_pnum,
&vm::o_pnil,
&vm::o_pstr,
&vm::o_newv,
&vm::o_newh,
&vm::o_newf,
&vm::o_happ,
&vm::o_para,
&vm::o_deft,
&vm::o_dyn,
&vm::o_lnot,
&vm::o_usub,
&vm::o_bnot,
&vm::o_btor,
&vm::o_btxor,
&vm::o_btand,
&vm::o_add,
&vm::o_sub,
&vm::o_mul,
&vm::o_div,
&vm::o_lnk,
&vm::o_addc,
&vm::o_subc,
&vm::o_mulc,
&vm::o_divc,
&vm::o_lnkc,
&vm::o_addeq,
&vm::o_subeq,
&vm::o_muleq,
&vm::o_diveq,
&vm::o_lnkeq,
&vm::o_bandeq,
&vm::o_boreq,
&vm::o_bxoreq,
&vm::o_addeqc,
&vm::o_subeqc,
&vm::o_muleqc,
&vm::o_diveqc,
&vm::o_lnkeqc,
&vm::o_addecp,
&vm::o_subecp,
&vm::o_mulecp,
&vm::o_divecp,
&vm::o_lnkecp,
&vm::o_meq,
&vm::o_eq,
&vm::o_neq,
&vm::o_less,
&vm::o_leq,
&vm::o_grt,
&vm::o_geq,
&vm::o_lessc,
&vm::o_leqc,
&vm::o_grtc,
&vm::o_geqc,
&vm::o_pop,
&vm::o_jmp,
&vm::o_jt,
&vm::o_jf,
&vm::o_cnt,
&vm::o_findex,
&vm::o_feach,
&vm::o_callg,
&vm::o_calll,
&vm::o_upval,
&vm::o_callv,
&vm::o_callvi,
&vm::o_callh,
&vm::o_callfv,
&vm::o_callfh,
&vm::o_callb,
&vm::o_slcbeg,
&vm::o_slcend,
&vm::o_slc,
&vm::o_slc2,
&vm::o_mcallg,
&vm::o_mcalll,
&vm::o_mupval,
&vm::o_mcallv,
&vm::o_mcallh,
&vm::o_ret
};
public: public:
/* constructor of vm instance */ /* constructor of vm instance */
@ -248,6 +343,11 @@ inline void vm::o_loadu() {
.upval()[imm[ctx.pc]&0xffff] = (ctx.top--)[0]; .upval()[imm[ctx.pc]&0xffff] = (ctx.top--)[0];
} }
inline void vm::o_dup() {
ctx.top[1] = ctx.top[0];
++ctx.top;
}
inline void vm::o_pnum() { inline void vm::o_pnum() {
(++ctx.top)[0] = var::num(const_number[imm[ctx.pc]]); (++ctx.top)[0] = var::num(const_number[imm[ctx.pc]]);
} }

View File

@ -18,7 +18,7 @@ var table_character_set = [
"┷", "┳", "⊥", "﹃", "﹄", "╮", "╭", "╯", "╰", "" "┷", "┳", "⊥", "﹃", "﹄", "╮", "╭", "╯", "╰", ""
]; ];
var selection_box = ["○", "◉", "☐", "▣"]; var selection_box = ["○", "◉", "☐", "▣", "☑", "☒"];
var char_ttf=[ var char_ttf=[
[" "," "," "," "," "," "], [" "," "," "," "," "," "],

View File

@ -7,8 +7,8 @@ use std.io;
use std.unix; use std.unix;
use std.math; use std.math;
var is_windows_platform=os.platform()=="windows"; var is_windows_platform = os.platform()=="windows";
var is_macos_platform=os.platform()=="macOS"; var is_macos_platform = os.platform()=="macOS";
if (is_windows_platform) { if (is_windows_platform) {
runtime.windows.set_utf8_output(); runtime.windows.set_utf8_output();
@ -17,72 +17,72 @@ if (is_windows_platform) {
var cpu_stat = func() { var cpu_stat = func() {
if (is_windows_platform or is_macos_platform) if (is_windows_platform or is_macos_platform)
return nil; return nil;
var cpu=split("\n",io.readfile("/proc/stat"))[0]; var cpu = split("\n", io.readfile("/proc/stat"))[0];
cpu=split(" ",cpu); cpu = split(" ", cpu);
cpu={ cpu = {
name:cpu[0], name: cpu[0],
user:cpu[1], user: cpu[1],
nice:cpu[2], nice: cpu[2],
system:cpu[3], system: cpu[3],
idle:cpu[4], idle: cpu[4],
iowait:cpu[5], iowait: cpu[5],
irq:cpu[6], irq: cpu[6],
softirq:cpu[7], softirq: cpu[7],
}; };
return cpu; return cpu;
} }
var cpu_occupation = func() { var cpu_occupation = func() {
var first_in=1; var first_in = 1;
while(1) { while(1) {
var cpu0=cpu_stat(); var cpu0 = cpu_stat();
if (first_in) { if (first_in) {
unix.sleep(0.1); unix.sleep(0.1);
first_in=0; first_in = 0;
} else { } else {
for(var i=0;i<10;i+=1) { for(var i = 0; i < 10; i += 1) {
unix.sleep(0.1); unix.sleep(0.1);
coroutine.yield(nil); coroutine.yield(nil);
} }
} }
var cpu1=cpu_stat(); var cpu1 = cpu_stat();
if (is_windows_platform or is_macos_platform) { if (is_windows_platform or is_macos_platform) {
coroutine.yield(0); coroutine.yield(0);
continue; continue;
} }
var t0=cpu0.user+cpu0.nice+cpu0.system+cpu0.idle+cpu0.iowait+cpu0.irq+cpu0.softirq; var t0 = cpu0.user+cpu0.nice+cpu0.system+cpu0.idle+cpu0.iowait+cpu0.irq+cpu0.softirq;
var t1=cpu1.user+cpu1.nice+cpu1.system+cpu1.idle+cpu1.iowait+cpu1.irq+cpu1.softirq; var t1 = cpu1.user+cpu1.nice+cpu1.system+cpu1.idle+cpu1.iowait+cpu1.irq+cpu1.softirq;
var interval=cpu1.idle-cpu0.idle; var interval = cpu1.idle-cpu0.idle;
coroutine.yield(t0==t1?0:(1-interval/(t1-t0))*100); coroutine.yield(t0==t1? 0:(1-interval/(t1-t0))*100);
} }
} }
var mem_occupation = func() { var mem_occupation = func() {
if (is_windows_platform or is_macos_platform) if (is_windows_platform or is_macos_platform)
return {MemTotal:math.inf,MemFree:math.inf}; return {MemTotal:math.inf,MemFree:math.inf};
var meminfo=split("\n",io.readfile("/proc/meminfo")); var meminfo = split("\n",io.readfile("/proc/meminfo"));
var mem_res={}; var mem_res = {};
forindex(var i;meminfo) { forindex(var i; meminfo) {
var tmp=split(" ",meminfo[i])[0:1]; var tmp = split(" ", meminfo[i])[0:1];
tmp[0]=substr(tmp[0],0,size(tmp[0])-1); tmp[0] = substr(tmp[0], 0, size(tmp[0])-1);
mem_res[tmp[0]]=num(tmp[1]); mem_res[tmp[0]] = num(tmp[1]);
} }
return mem_res; return mem_res;
} }
var random_generator = func() { var random_generator = func() {
var rise=[" ","▁","▂","▃","▄","▅","▆","▇","█"]; var rise = [" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
var total=0; var total = 0;
var statistics=[]; var statistics = [];
setsize(statistics,70); setsize(statistics, 70);
while(1) { while(1) {
for(var i=0;i<10;i+=1) { for(var i=0;i<10;i+=1) {
total+=1; total+=1;
var u=rand()*rand()*(rand()>0.5?-1:1); var u=rand()*rand()*(rand()>0.5?-1:1);
statistics[int(size(statistics)/2+u*size(statistics)/2)]+=1; statistics[int(size(statistics)/2+u*size(statistics)/2)]+=1;
} }
var s=["","",""]; var s = ["", "", ""];
foreach(var st;statistics) { foreach(var st; statistics) {
var max_rate=100/size(statistics); var max_rate=100/size(statistics);
var rate=st/total*100; var rate=st/total*100;
for(var i=size(s)-1;i>=0;i-=1) { for(var i=size(s)-1;i>=0;i-=1) {
@ -97,12 +97,12 @@ var random_generator = func() {
} }
var tmp=""; var tmp="";
for(var i=0;i<size(statistics);i+=1) { for(var i=0;i<size(statistics);i+=1) {
tmp~="-"; tmp~="";
} }
println("\e[16;1H \e[32m|",s[0],"|\e[0m"); println("\e[16;1H \e[32m│", s[0], "│\e[0m");
println("\e[17;1H \e[32m|",s[1],"|\e[0m"); println("\e[17;1H \e[32m│", s[1], "│\e[0m");
println("\e[18;1H \e[32m|",s[2],"|\e[0m"); println("\e[18;1H \e[32m│", s[2], "│\e[0m");
println("\e[19;1H \e[32m+"~tmp~"+\e[0m"); println("\e[19;1H \e[32m╰", tmp, "╯\e[0m");
coroutine.yield(); coroutine.yield();
} }
} }
@ -164,7 +164,7 @@ func() {
var tmp=""; var tmp="";
for(var i=0;i<70;i+=1) { for(var i=0;i<70;i+=1) {
tmp~="-"; tmp~="";
} }
var s=["","",""]; var s=["","",""];
@ -181,11 +181,11 @@ func() {
} }
} }
} }
println("\e[7;1H \e[32m+"~tmp~"+\e[0m"); println("\e[7;1H \e[32m╭"~tmp~"╮\e[0m");
println("\e[8;1H \e[32m|",s[0],"|\e[0m"); println("\e[8;1H \e[32m│",s[0],"│\e[0m");
println("\e[9;1H \e[32m|",s[1],"|\e[0m"); println("\e[9;1H \e[32m│",s[1],"│\e[0m");
println("\e[10;1H \e[32m|",s[2],"|\e[0m"); println("\e[10;1H \e[32m│",s[2],"│\e[0m");
println("\e[11;1H \e[32m+"~tmp~"+\e[0m"); println("\e[11;1H \e[32m├"~tmp~"┤\e[0m");
var s=["","",""]; var s=["","",""];
foreach(var occ;mem_occupation_log) { foreach(var occ;mem_occupation_log) {
@ -201,10 +201,10 @@ func() {
} }
} }
} }
println("\e[12;1H \e[32m|",s[0],"|\e[0m"); println("\e[12;1H \e[32m│",s[0],"│\e[0m");
println("\e[13;1H \e[32m|",s[1],"|\e[0m"); println("\e[13;1H \e[32m│",s[1],"│\e[0m");
println("\e[14;1H \e[32m|",s[2],"|\e[0m"); println("\e[14;1H \e[32m│",s[2],"│\e[0m");
println("\e[15;1H \e[32m+"~tmp~"+\e[0m"); println("\e[15;1H \e[32m├"~tmp~"┤\e[0m");
println("\e[20;1H Press 'q' to quit."); println("\e[20;1H Press 'q' to quit.");
} }

View File

@ -267,3 +267,16 @@ for(var i = 1; i<=10; i += 1) {
die("test failed: expect " ~ i ~ ", but get " ~ closure_tester[1]()); die("test failed: expect " ~ i ~ ", but get " ~ closure_tester[1]());
} }
} }
func() {
var a = nil;
var b = nil;
var c = nil;
println(a??b??c??"a??b??c?? -> should print this text");
var a = {b: 2};
println(a?.b); # should be 2
var a = nil;
println(a?.b); # should be nil
}();