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")
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
set(CMAKE_BUILD_TYPE "Release")

View File

@ -112,7 +112,12 @@ build/nasal_type.o:\
src/nasal_type.h src/nasal_type.cpp | build
$(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
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::condition_and: std::cout << "and"; 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);
push_indent();
@ -241,6 +242,13 @@ bool ast_dumper::visit_call_hash(call_hash* node) {
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) {
dump_indent();
std::cout << "call_vector";

View File

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

View File

@ -26,6 +26,7 @@ public:
virtual bool visit_unary_operator(unary_operator*);
virtual bool visit_call_expr(call_expr*);
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_function(call_function*);
virtual bool visit_slice_vector(slice_vector*);

View File

@ -23,4 +23,40 @@ cli_config parse(const std::vector<std::string>& args) {
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_set>
#include <vector>
#include <iostream>
namespace nasal::cli {
@ -67,4 +68,6 @@ const std::unordered_map<std::string, option> cli_options = {
cli_config parse(const std::vector<std::string>&);
std::ostream& help(std::ostream&);
}

View File

@ -18,45 +18,9 @@
#include "repl/repl.h"
#include "cli/cli.h"
#include <unordered_map>
#include <thread>
#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) {
out
<< "\n"
@ -67,7 +31,8 @@ std::ostream& logo(std::ostream& out) {
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
<< "\n"
<< "ver : " << __nasver__
<< " " << nasal::util::get_platform() << " " << nasal::util::get_arch()
<< " " << nasal::util::get_platform()
<< " " << nasal::util::get_arch()
<< " (" << __DATE__ << " " << __TIME__ << ")\n"
<< "std : c++ " << __cplusplus << "\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"
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
<< "\n"
<< "presented by fgprc members\n"
<< " - http://fgprc.org\n"
<< " - http://fgprc.org.cn\n"
<< "presented by fgprc members:\n"
<< " - http://fgprc.org\n"
<< " - http://fgprc.org.cn\n"
<< "\n"
<< "input <nasal -h> to get help .\n\n";
return out;
@ -96,7 +61,8 @@ std::ostream& version(std::ostream& out) {
}
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";
return out;
}
@ -195,7 +161,7 @@ i32 main(i32 argc, const char* argv[]) {
// run directly or show help
if (argc==2) {
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)) {
std::clog << version;
} 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);
}
void null_access::accept(ast_visitor* visitor) {
visitor->visit_null_access(this);
}
call_vector::~call_vector() {
for(auto i : calls) {
delete i;

View File

@ -23,6 +23,7 @@ enum class expr_type {
ast_pair, // pair of key and value in hashmap
ast_call, // mark a sub-tree of calling an identifier
ast_callh, // id.name
ast_null_access, // id?.name
ast_callv, // id[index]
ast_callf, // id()
ast_subvec, // id[index:index]
@ -302,7 +303,8 @@ public:
bitwise_xor,
bitwise_and,
condition_and,
condition_or
condition_or,
null_chain
};
private:
@ -389,6 +391,19 @@ public:
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 {
private:
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;
case expr_type::ast_callf:
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;
}
}
@ -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());
}
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) {
// maybe this place can use callv-const if ast's first child is ast_num
if (node->get_slices().size()==1 &&
@ -455,6 +475,8 @@ void codegen::mcall(expr* node) {
call_vector_gen(reinterpret_cast<call_vector*>(tmp)); break;
case expr_type::ast_callf:
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;
}
}
@ -467,6 +489,8 @@ void codegen::mcall(expr* node) {
mcall_vec(reinterpret_cast<call_vector*>(tmp)); break;
case expr_type::ast_callf:
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:
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());
emit(op_btand, 0, node->get_location());
return;
case binary_operator::binary_type::null_chain:
null_chain_gen(node);
return;
default: break;
}
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) {
calc_gen(node->get_condition());
usize label_jump_false = code.size();

View File

@ -123,6 +123,7 @@ private:
void call_gen(call_expr*);
void call_identifier(identifier*);
void call_hash_gen(call_hash*);
void null_access_gen(null_access*);
void call_vector_gen(call_vector*);
void call_func_gen(call_function*);
void mcall(expr*);
@ -148,6 +149,7 @@ private:
void and_gen(binary_operator*);
void unary_gen(unary_operator*);
void binary_gen(binary_operator*);
void null_chain_gen(binary_operator*);
void trino_gen(ternary_operator*);
void calc_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) {
break;
}
std::clog << " " << oprand_name_table[i.first] << " : ";
std::clog << i.second << " (" << rate << "%)\n";
std::clog << " ";
std::clog << operand_name_table.at(static_cast<op_code_type>(i.first));
std::clog << " : " << i.second << " (" << rate << "%)\n";
}
std::clog << " total : " << total << '\n';
}

View File

@ -40,55 +40,6 @@ public:
};
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:
enum class cmd_kind {
cmd_error,

View File

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

View File

@ -35,12 +35,16 @@ bool lexer::is_str(char c) {
return c=='\'' || c=='\"' || c=='`';
}
bool lexer::is_quesmark(char c) {
return c=='?';
}
bool lexer::is_single_opr(char c) {
return (
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) {
// search token type from mapper
// if cannot find, just return 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() {
u64 begin_line = line;
u64 begin_column = column;
@ -398,6 +422,8 @@ const error& lexer::scan(const std::string& file) {
toks.push_back(num_gen());
} else if (is_str(res[ptr])) {
toks.push_back(str_gen());
} else if (is_quesmark(res[ptr])) {
toks.push_back(quesmark_gen());
} else if (is_single_opr(res[ptr])) {
toks.push_back(single_opr());
} else if (res[ptr]=='.') {

View File

@ -50,6 +50,8 @@ enum class tok {
tk_dot, // .
tk_ellipsis, // ...
tk_quesmark, // ?
tk_quesques, // ??
tk_quesdot, // ?.
tk_colon, // :
tk_add, // operator +
tk_sub, // operator -
@ -79,9 +81,10 @@ enum class tok {
};
struct token {
span loc; // location
tok type; // token type
span loc; // location
tok type; // token type
std::string str; // content
token() = default;
token(const token&) = default;
};
@ -94,10 +97,12 @@ private:
std::string filename;
std::string res;
private:
error err;
u64 invalid_char;
std::vector<token> toks;
private:
const std::unordered_map<std::string, tok> token_mapper = {
{"use" , tok::tk_use },
{"true" , tok::tk_true },
@ -128,6 +133,8 @@ private:
{"." , tok::tk_dot },
{"..." , tok::tk_ellipsis},
{"?" , tok::tk_quesmark},
{"??" , tok::tk_quesques},
{"?." , tok::tk_quesdot },
{":" , tok::tk_colon },
{"+" , tok::tk_add },
{"-" , tok::tk_sub },
@ -155,6 +162,7 @@ private:
{">=" , tok::tk_geq }
};
private:
tok get_type(const std::string&);
bool skip(char);
bool is_id(char);
@ -162,6 +170,7 @@ private:
bool is_oct(char);
bool is_dec(char);
bool is_str(char);
bool is_quesmark(char);
bool is_single_opr(char);
bool is_calc_opr(char);
@ -173,14 +182,17 @@ private:
token id_gen();
token num_gen();
token str_gen();
token quesmark_gen();
token single_opr();
token dots();
token calc_opr();
public:
lexer(): line(1), column(0), ptr(0),
filename(""), res(""), invalid_char(0) {}
filename(""), res(""),
invalid_char(0) {}
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 {
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,
const std::string* string_list,
const nasal_builtin_table* native_table,
@ -58,7 +33,7 @@ void codestream::dump(std::ostream& out) const {
}
// dump operand name
out << " " << oprand_name_table[op] << " ";
out << " " << operand_name_table.at(static_cast<op_code_type>(op)) << " ";
switch(op) {
case op_addeq:

View File

@ -14,6 +14,7 @@ enum op_code_type: u8 {
op_loadg, // load global value
op_loadl, // load local value
op_loadu, // load upvalue
op_dup, // copy value on stack top
op_pnum, // push constant number to the stack
op_pnil, // push constant nil to the stack
op_pstr, // push constant std::string to the stack
@ -97,6 +98,97 @@ enum op_code_type: u8 {
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 {
u8 op; // opcode
u16 fidx; // source code file index
@ -127,6 +219,4 @@ public:
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_str: die(thisspan, "expected string"); 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;
}
@ -94,7 +98,8 @@ bool parse::lookahead(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) {
@ -564,7 +569,7 @@ expr* parse::and_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) {
auto tmp = new binary_operator(toks[ptr].loc);
switch(toks[ptr].type) {
@ -578,6 +583,21 @@ expr* parse::cmp_expr() {
}
tmp->set_left(node);
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());
update_location(tmp);
node = tmp;
@ -718,6 +738,7 @@ call* parse::call_scalar() {
case tok::tk_lcurve: return callf(); break;
case tok::tk_lbracket: return callv(); break;
case tok::tk_dot: return callh(); break;
case tok::tk_quesdot: return null_access_call(); break;
default: break;
}
// unreachable
@ -733,6 +754,15 @@ call_hash* parse::callh() {
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() {
// panic set for this token is not ','
// this is the FIRST set of subvec

View File

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

View File

@ -429,28 +429,94 @@ void vm::run(const codegen& gen,
#ifndef _MSC_VER
// using labels as values/computed goto
const void* oprs[] = {
&&vmexit, &&repl, &&intl, &&loadg,
&&loadl, &&loadu, &&pnum, &&pnil,
&&pstr, &&newv, &&newh, &&newf,
&&happ, &&para, &&deft, &&dyn,
&&lnot, &&usub, &&bnot, &&btor,
&&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
&&vmexit,
&&repl,
&&intl,
&&loadg,
&&loadl,
&&loadu,
&&dup,
&&pnum,
&&pnil,
&&pstr,
&&newv,
&&newh,
&&newf,
&&happ,
&&para,
&&deft,
&&dyn,
&&lnot,
&&usub,
&&bnot,
&&btor,
&&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;
for(const auto& i : gen.codes()) {
@ -460,56 +526,9 @@ void vm::run(const codegen& gen,
// goto the first operand
goto *code[ctx.pc];
#else
typedef void (vm::*nafunc)();
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;
std::vector<nasal_vm_func> code;
for(const auto& i : gen.codes()) {
code.push_back(oprs[i.op]);
code.push_back(operand_function[i.op]);
imm.push_back(i.num);
}
while(code[ctx.pc]) {
@ -520,7 +539,7 @@ void vm::run(const codegen& gen,
++ctx.pc;
}
#endif
// all nasal programs should end here
vmexit:
if (verbose) {
ngc.info();
@ -551,6 +570,7 @@ intl: exec_nodie(o_intl ); // -0
loadg: exec_nodie(o_loadg ); // -1
loadl: exec_nodie(o_loadl ); // -1
loadu: exec_nodie(o_loadu ); // -1
dup: exec_check(o_dup ); // +1
pnum: exec_check(o_pnum ); // +1
pnil: exec_check(o_pnil ); // +1
pstr: exec_check(o_pstr ); // +1

View File

@ -93,6 +93,7 @@ protected:
inline void o_loadg();
inline void o_loadl();
inline void o_loadu();
inline void o_dup();
inline void o_pnum();
inline void o_pnil();
inline void o_pstr();
@ -175,6 +176,100 @@ protected:
inline void o_mcallh();
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:
/* constructor of vm instance */
@ -248,6 +343,11 @@ inline void vm::o_loadu() {
.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() {
(++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=[
[" "," "," "," "," "," "],

View File

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