Merge pull request #38 from ValKmjolnir/develop
✨ optimize import module & add limited execution mode (disable unsafe system api)
This commit is contained in:
commit
2e321fc4d6
26
src/main.cpp
26
src/main.cpp
|
@ -30,6 +30,7 @@ const u32 VM_SYMINFO = 1<<7;
|
|||
const u32 VM_PROFILE = 1<<8;
|
||||
const u32 VM_PROF_ALL = 1<<9;
|
||||
const u32 VM_REF_FILE = 1<<10;
|
||||
const u32 VM_LIMIT = 1<<11;
|
||||
|
||||
std::ostream& help(std::ostream& out) {
|
||||
out
|
||||
|
@ -59,6 +60,7 @@ std::ostream& help(std::ostream& out) {
|
|||
<< " --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."
|
||||
<< "file:\n"
|
||||
<< " <filename> | execute file.\n"
|
||||
<< "argv:\n"
|
||||
|
@ -75,13 +77,18 @@ std::ostream& logo(std::ostream& out) {
|
|||
<< " / \\/ / _` / __|/ _` | |\n"
|
||||
<< " / /\\ / (_| \\__ \\ (_| | |\n"
|
||||
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||
<< "ver : " << __nasver << " (" << __DATE__ << " " << __TIME__ << ")\n"
|
||||
<< "\n"
|
||||
<< "ver : " << __nasver__
|
||||
<< " " << nasal::get_platform() << " " << nasal::get_arch()
|
||||
<< " (" << __DATE__ << " " << __TIME__ << ")\n"
|
||||
<< "std : c++ " << __cplusplus << "\n"
|
||||
<< "core : " << std::thread::hardware_concurrency() << " core(s)\n"
|
||||
<< "repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||
<< "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||
<< "\n"
|
||||
<< "presented by fgprc members - http://fgprc.org.cn\n"
|
||||
<< "\n"
|
||||
<< "input <nasal -h> to get help .\n\n";
|
||||
return out;
|
||||
}
|
||||
|
@ -95,7 +102,8 @@ std::ostream& version(std::ostream& out) {
|
|||
if (num<0.01) {
|
||||
nasal::parse::easter_egg();
|
||||
}
|
||||
out << "nasal interpreter version " << __nasver;
|
||||
out << "nasal interpreter version " << __nasver__;
|
||||
out << " " << nasal::get_platform() << " " << nasal::get_arch();
|
||||
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||
return out;
|
||||
}
|
||||
|
@ -127,12 +135,11 @@ void execute(
|
|||
// parser gets lexer's token list to compile
|
||||
parse.compile(lex).chkerr();
|
||||
if (cmd&VM_RAW_AST) {
|
||||
auto dumper = std::unique_ptr<nasal::ast_dumper>(new nasal::ast_dumper);
|
||||
dumper->dump(parse.tree());
|
||||
nasal::ast_dumper().dump(parse.tree());
|
||||
}
|
||||
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
ld.link(parse, file, cmd&VM_DETAIL).chkerr();
|
||||
ld.link(parse, cmd&VM_DETAIL).chkerr();
|
||||
if (cmd&VM_REF_FILE) {
|
||||
if (ld.get_file_list().size()) {
|
||||
std::cout << "referenced file(s):\n";
|
||||
|
@ -146,12 +153,11 @@ void execute(
|
|||
auto opt = std::unique_ptr<nasal::optimizer>(new nasal::optimizer);
|
||||
opt->do_optimization(parse.tree());
|
||||
if (cmd&VM_AST) {
|
||||
auto dumper = std::unique_ptr<nasal::ast_dumper>(new nasal::ast_dumper);
|
||||
dumper->dump(parse.tree());
|
||||
nasal::ast_dumper().dump(parse.tree());
|
||||
}
|
||||
|
||||
// code generator gets parser's ast and import file list to generate code
|
||||
gen.compile(parse, ld, false).chkerr();
|
||||
gen.compile(parse, ld, false, cmd&VM_LIMIT).chkerr();
|
||||
if (cmd&VM_CODE) {
|
||||
gen.print(std::cout);
|
||||
}
|
||||
|
@ -167,6 +173,7 @@ void execute(
|
|||
} else if (cmd&VM_TIME || cmd&VM_EXEC) {
|
||||
auto runtime = std::unique_ptr<nasal::vm>(new nasal::vm);
|
||||
runtime->set_detail_report_info(cmd&VM_DETAIL);
|
||||
runtime->set_limit_mode_flag(cmd&VM_LIMIT);
|
||||
runtime->run(gen, ld, argv);
|
||||
}
|
||||
|
||||
|
@ -223,7 +230,8 @@ i32 main(i32 argc, const char* argv[]) {
|
|||
{"--prof", VM_PROFILE},
|
||||
{"--prof-all", VM_PROF_ALL},
|
||||
{"-f", VM_REF_FILE},
|
||||
{"--ref-file", VM_REF_FILE}
|
||||
{"--ref-file", VM_REF_FILE},
|
||||
{"--limit", VM_LIMIT|VM_EXEC}
|
||||
};
|
||||
u32 cmd = 0;
|
||||
std::string filename = "";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef __nasver
|
||||
#define __nasver "11.1"
|
||||
#ifndef __nasver__
|
||||
#define __nasver__ "11.1"
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -34,7 +34,8 @@ bool is_aarch64();
|
|||
bool is_ia64();
|
||||
bool is_powerpc();
|
||||
bool is_superh();
|
||||
|
||||
const char* get_platform();
|
||||
const char* get_arch();
|
||||
|
||||
// virtual machine stack depth, both global depth and value stack depth
|
||||
const u32 STACK_DEPTH = 4096;
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
var builtin_unsafe(context* ctx, gc* ngc) {
|
||||
return nas_err(
|
||||
"unsafe_redirect",
|
||||
"you are using unsafe system api under limited mode!"
|
||||
);
|
||||
}
|
||||
|
||||
var builtin_print(context* ctx, gc* ngc) {
|
||||
for(auto& i : ctx->localr[1].vec().elems) {
|
||||
std::cout << i;
|
||||
|
@ -447,35 +454,11 @@ var builtin_sleep(context* ctx, gc* ngc) {
|
|||
}
|
||||
|
||||
var builtin_platform(context* ctx, gc* ngc) {
|
||||
if (is_windows()) {
|
||||
return ngc->newstr("windows");
|
||||
} else if (is_linux()) {
|
||||
return ngc->newstr("linux");
|
||||
} else if (is_macos()) {
|
||||
return ngc->newstr("macOS");
|
||||
}
|
||||
return ngc->newstr("unknown");
|
||||
return ngc->newstr(get_platform());
|
||||
}
|
||||
|
||||
var builtin_arch(context* ctx, gc* ngc) {
|
||||
if (is_x86()) {
|
||||
return ngc->newstr("x86");
|
||||
} else if (is_x86_64()) {
|
||||
return ngc->newstr("x86-64");
|
||||
} else if (is_amd64()) {
|
||||
return ngc->newstr("amd64");
|
||||
} else if (is_arm()) {
|
||||
return ngc->newstr("arm");
|
||||
} else if (is_aarch64()) {
|
||||
return ngc->newstr("aarch64");
|
||||
} else if (is_ia64()) {
|
||||
return ngc->newstr("ia64");
|
||||
} else if (is_powerpc()) {
|
||||
return ngc->newstr("powerpc");
|
||||
} else if (is_superh()) {
|
||||
return ngc->newstr("superh");
|
||||
}
|
||||
return ngc->newstr("unknown");
|
||||
return ngc->newstr(get_arch());
|
||||
}
|
||||
|
||||
// md5 related functions
|
||||
|
@ -683,7 +666,7 @@ var builtin_logtime(context* ctx, gc* ngc) {
|
|||
tm* tm_t = localtime(&t);
|
||||
char s[64];
|
||||
snprintf(
|
||||
s,64,"%d-%.2d-%.2d %.2d:%.2d:%.2d",
|
||||
s, 64, "%d-%.2d-%.2d %.2d:%.2d:%.2d",
|
||||
tm_t->tm_year+1900,
|
||||
tm_t->tm_mon+1,
|
||||
tm_t->tm_mday,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
var builtin_unsafe(context*, gc*);
|
||||
var builtin_print(context*, gc*);
|
||||
var builtin_println(context*, gc*);
|
||||
var builtin_exit(context*, gc*);
|
||||
|
|
|
@ -11,12 +11,18 @@ void codegen::init_file_map(const std::vector<std::string>& file_list) {
|
|||
|
||||
void codegen::load_native_function_table(nasal_builtin_table* table) {
|
||||
for(usize i = 0; table[i].func; ++i) {
|
||||
// check confliction
|
||||
if (native_function_mapper.count(table[i].name)) {
|
||||
err.err("code", "\"" + std::string(table[i].name) + "\" conflicts.");
|
||||
continue;
|
||||
}
|
||||
native_function.push_back(table[i]);
|
||||
if (flag_limited_mode && unsafe_system_api.count(table[i].name)) {
|
||||
native_function.push_back({"__unsafe_redirect", builtin_unsafe});
|
||||
} else {
|
||||
native_function.push_back(table[i]);
|
||||
}
|
||||
auto index = native_function_mapper.size();
|
||||
// insert into mapper
|
||||
native_function_mapper[table[i].name] = index;
|
||||
}
|
||||
}
|
||||
|
@ -1302,10 +1308,14 @@ void codegen::ret_gen(return_expr* node) {
|
|||
emit(op_ret, 0, node->get_location());
|
||||
}
|
||||
|
||||
const error& codegen::compile(parse& parse, linker& import, bool repl_flag) {
|
||||
const error& codegen::compile(parse& parse,
|
||||
linker& import,
|
||||
bool repl_flag,
|
||||
bool limit_mode) {
|
||||
need_repl_output = repl_flag;
|
||||
flag_limited_mode = limit_mode;
|
||||
init_native_function();
|
||||
init_file_map(import.get_file_list());
|
||||
need_repl_output = repl_flag;
|
||||
|
||||
in_foreach_loop_level.push_back(0);
|
||||
|
||||
|
|
|
@ -37,6 +37,24 @@ private:
|
|||
|
||||
// repl output flag, will generate op_repl to output stack top value if true
|
||||
bool need_repl_output;
|
||||
// limit mode flag
|
||||
bool flag_limited_mode;
|
||||
const std::unordered_set<std::string> unsafe_system_api = {
|
||||
// builtin
|
||||
"__system", "__input",
|
||||
// io
|
||||
"__fout", "__open", "__write", "__stat"
|
||||
// bits
|
||||
"__fld", "__sfld", "__setfld",
|
||||
"__buf",
|
||||
// fg
|
||||
"__logprint",
|
||||
// dylib
|
||||
"__dlopen", "__dlclose", "__dlcallv", "__dlcall",
|
||||
// unix
|
||||
"__pipe", "__fork", "__waitpid", "__chdir",
|
||||
"__environ", "__getcwd", "__getenv"
|
||||
};
|
||||
|
||||
// file mapper for file -> index
|
||||
std::unordered_map<std::string, usize> file_map;
|
||||
|
@ -141,7 +159,7 @@ public:
|
|||
|
||||
public:
|
||||
codegen() = default;
|
||||
const error& compile(parse&, linker&, bool);
|
||||
const error& compile(parse&, linker&, bool, bool);
|
||||
void print(std::ostream&);
|
||||
void symbol_dump(std::ostream&) const;
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@ protected:
|
|||
std::vector<std::string> res;
|
||||
|
||||
public:
|
||||
flstream():file("") {}
|
||||
flstream(): file("") {}
|
||||
void load(const std::string&);
|
||||
const std::string& operator[](usize n) const {return res[n];}
|
||||
const auto& name() const {return file;}
|
||||
|
@ -39,23 +39,23 @@ public:
|
|||
usize size() const {return res.size();}
|
||||
};
|
||||
|
||||
class error:public flstream {
|
||||
class error: public flstream {
|
||||
private:
|
||||
u32 cnt; // counter for errors
|
||||
|
||||
std::string identation(usize len) {
|
||||
return std::string(len,' ');
|
||||
return std::string(len, ' ');
|
||||
}
|
||||
std::string leftpad(u32 num, usize len) {
|
||||
auto tmp = std::to_string(num);
|
||||
while(tmp.length()<len) {
|
||||
tmp=" "+tmp;
|
||||
tmp = " "+tmp;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public:
|
||||
error():cnt(0) {}
|
||||
error(): cnt(0) {}
|
||||
void err(const std::string&, const std::string&);
|
||||
void warn(const std::string&, const std::string&);
|
||||
void err(const std::string&, const span&, const std::string&);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
linker::linker(): show_path_flag(false), library_loaded(false), this_file("") {
|
||||
linker::linker(): show_path_flag(false), this_file("") {
|
||||
const auto seperator = is_windows()? ';':':';
|
||||
const auto PATH = std::string(getenv("PATH"));
|
||||
usize last = 0, position = PATH.find(seperator, 0);
|
||||
|
@ -155,7 +155,7 @@ std::string linker::generate_self_import_path(const std::string& filename) {
|
|||
return res + "[" + filename + "]";
|
||||
}
|
||||
|
||||
void linker::link(code_block* new_tree_root, code_block* old_tree_root) {
|
||||
void linker::merge_tree(code_block* new_tree_root, code_block* old_tree_root) {
|
||||
// add children of add_root to the back of root
|
||||
for(auto& i : old_tree_root->get_expressions()) {
|
||||
new_tree_root->add_expression(i);
|
||||
|
@ -179,32 +179,48 @@ code_block* linker::import_regular_file(
|
|||
// check self import, avoid infinite loading loop
|
||||
if (check_self_import(filename)) {
|
||||
err.err("link",
|
||||
"self-referenced module <" + filename + ">:\n" +
|
||||
" reference path: " + generate_self_import_path(filename)
|
||||
node->get_location(),
|
||||
"self-referenced module <" + filename + ">, " +
|
||||
"reference path: " + generate_self_import_path(filename)
|
||||
);
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
check_exist_or_record_file(filename);
|
||||
|
||||
|
||||
module_load_stack.push_back(filename);
|
||||
// avoid stack overflow
|
||||
if (module_load_stack.size()>MAX_RECURSION_DEPTH) {
|
||||
err.err("link",
|
||||
node->get_location(),
|
||||
"too deep module import stack (>" +
|
||||
std::to_string(MAX_RECURSION_DEPTH) + ")."
|
||||
);
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
// start importing...
|
||||
lexer nasal_lexer;
|
||||
parse nasal_parser;
|
||||
if (nasal_lexer.scan(filename).geterr()) {
|
||||
err.err("link", "error occurred when analysing <" + filename + ">");
|
||||
err.err("link",
|
||||
node->get_location(),
|
||||
"error occurred when analysing <" + filename + ">"
|
||||
);
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
if (nasal_parser.compile(nasal_lexer).geterr()) {
|
||||
err.err("link", "error occurred when analysing <" + filename + ">");
|
||||
err.err("link",
|
||||
node->get_location(),
|
||||
"error occurred when analysing <" + filename + ">"
|
||||
);
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
// swap result out
|
||||
auto parse_result = nasal_parser.swap(nullptr);
|
||||
|
||||
// check if parse result has 'import'
|
||||
auto result = load(parse_result, filename);
|
||||
load(parse_result, filename);
|
||||
module_load_stack.pop_back();
|
||||
return result;
|
||||
return parse_result;
|
||||
}
|
||||
|
||||
code_block* linker::import_nasal_lib() {
|
||||
|
@ -238,10 +254,12 @@ code_block* linker::import_nasal_lib() {
|
|||
// swap result out
|
||||
auto parse_result = nasal_parser.swap(nullptr);
|
||||
// check if library has 'import' (in fact it should not)
|
||||
return load(parse_result, path);
|
||||
load(parse_result, path);
|
||||
return parse_result;
|
||||
}
|
||||
|
||||
std::string linker::generate_module_name(const std::string& file_path) {
|
||||
// import("...") may trigger this error module name
|
||||
auto error_name = "module@[" + file_path + "]";
|
||||
if (!file_path.length()) {
|
||||
return error_name;
|
||||
|
@ -316,13 +334,19 @@ return_expr* linker::generate_module_return(code_block* block) {
|
|||
}
|
||||
|
||||
definition_expr* linker::generate_module_definition(code_block* block) {
|
||||
// generate ast node like this:
|
||||
// var {module_name} = (func() {
|
||||
// ... # module itself
|
||||
// })();
|
||||
auto def = new definition_expr(block->get_location());
|
||||
def->set_identifier(new identifier(
|
||||
block->get_location(),
|
||||
generate_module_name(block->get_location().file)
|
||||
));
|
||||
|
||||
// (func() {...})();
|
||||
auto call = new call_expr(block->get_location());
|
||||
// func() {...}
|
||||
auto func = new function(block->get_location());
|
||||
func->set_code_block(block);
|
||||
func->get_code_block()->add_expression(generate_module_return(block));
|
||||
|
@ -333,18 +357,7 @@ definition_expr* linker::generate_module_definition(code_block* block) {
|
|||
return def;
|
||||
}
|
||||
|
||||
code_block* linker::load(code_block* program_root, const std::string& filename) {
|
||||
auto tree = new code_block({0, 0, 0, 0, filename});
|
||||
// load library, this ast will be linked with root directly
|
||||
// so no extra namespace is generated
|
||||
if (!library_loaded) {
|
||||
auto nasal_lib_code_block = import_nasal_lib();
|
||||
// insert nasal lib code to the back of tree
|
||||
link(tree, nasal_lib_code_block);
|
||||
delete nasal_lib_code_block;
|
||||
library_loaded = true;
|
||||
}
|
||||
|
||||
void linker::load(code_block* program_root, const std::string& filename) {
|
||||
// load imported modules
|
||||
std::unordered_set<std::string> used_modules = {};
|
||||
for(auto& import_node : program_root->get_expressions()) {
|
||||
|
@ -353,46 +366,46 @@ code_block* linker::load(code_block* program_root, const std::string& filename)
|
|||
}
|
||||
// parse file and get ast
|
||||
auto module_code_block = import_regular_file(import_node, used_modules);
|
||||
auto replace_node = new null_expr(import_node->get_location());
|
||||
// after importing the regular file as module, delete this node
|
||||
delete import_node;
|
||||
// and replace the node with null_expr node
|
||||
import_node = replace_node;
|
||||
|
||||
// avoid repeatedly importing the same module
|
||||
// avoid repeatedly importing the same module in one file
|
||||
const auto& module_path = module_code_block->get_location().file;
|
||||
if (used_modules.count(module_path)) {
|
||||
delete module_code_block;
|
||||
auto replace_node = new null_expr(import_node->get_location());
|
||||
// after importing the regular file as module, delete this node
|
||||
delete import_node;
|
||||
// and replace the node with null_expr node
|
||||
import_node = replace_node;
|
||||
continue;
|
||||
}
|
||||
|
||||
used_modules.insert(module_path);
|
||||
delete import_node;
|
||||
// then we generate a function warping the code block,
|
||||
// and export the necessary global symbols in this code block
|
||||
// by generate a return statement, with a hashmap return value
|
||||
used_modules.insert(module_path);
|
||||
tree->add_expression(generate_module_definition(module_code_block));
|
||||
import_node = generate_module_definition(module_code_block);
|
||||
}
|
||||
|
||||
// insert program root to the back of tree
|
||||
link(tree, program_root);
|
||||
return tree;
|
||||
}
|
||||
|
||||
const error& linker::link(
|
||||
parse& parse, const std::string& self, bool spath = false) {
|
||||
const error& linker::link(parse& parse, bool spath = false) {
|
||||
// switch for showing path when errors occur
|
||||
show_path_flag = spath;
|
||||
|
||||
// initializing file map
|
||||
this_file = self;
|
||||
imported_files = {self};
|
||||
module_load_stack = {self};
|
||||
this_file = parse.tree()->get_location().file;
|
||||
imported_files = {this_file};
|
||||
module_load_stack = {this_file};
|
||||
|
||||
// scan root and import files
|
||||
// then generate a new ast and return to import_ast
|
||||
auto new_tree_root = load(parse.tree(), self);
|
||||
auto old_tree_root = parse.swap(new_tree_root);
|
||||
delete old_tree_root;
|
||||
// dfs load file
|
||||
auto library = import_nasal_lib();
|
||||
// load used modules of this file
|
||||
load(parse.tree(), this_file);
|
||||
// then insert the whole tree into library tree root
|
||||
merge_tree(library, parse.tree());
|
||||
// swap tree root, and delete old root
|
||||
delete parse.swap(library);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace nasal {
|
|||
|
||||
class linker {
|
||||
private:
|
||||
const u32 MAX_RECURSION_DEPTH = 256;
|
||||
bool show_path_flag;
|
||||
bool library_loaded;
|
||||
std::string this_file;
|
||||
error err;
|
||||
std::vector<std::string> imported_files;
|
||||
|
@ -36,7 +36,7 @@ private:
|
|||
bool check_exist_or_record_file(const std::string&);
|
||||
bool check_self_import(const std::string&);
|
||||
std::string generate_self_import_path(const std::string&);
|
||||
void link(code_block*, code_block*);
|
||||
void merge_tree(code_block*, code_block*);
|
||||
std::string get_path(expr*);
|
||||
std::string find_real_file_path(const std::string&, const span&);
|
||||
code_block* import_regular_file(expr*, std::unordered_set<std::string>&);
|
||||
|
@ -44,11 +44,11 @@ private:
|
|||
std::string generate_module_name(const std::string&);
|
||||
return_expr* generate_module_return(code_block*);
|
||||
definition_expr* generate_module_definition(code_block*);
|
||||
code_block* load(code_block*, const std::string&);
|
||||
void load(code_block*, const std::string&);
|
||||
|
||||
public:
|
||||
linker();
|
||||
const error& link(parse&, const std::string&, bool);
|
||||
const error& link(parse&, bool);
|
||||
const auto& get_file_list() const {return imported_files;}
|
||||
};
|
||||
|
||||
|
|
|
@ -97,6 +97,38 @@ bool is_superh() {
|
|||
#endif
|
||||
}
|
||||
|
||||
const char* get_platform() {
|
||||
if (is_windows()) {
|
||||
return "windows";
|
||||
} else if (is_linux()) {
|
||||
return "linux";
|
||||
} else if (is_macos()) {
|
||||
return "macOS";
|
||||
}
|
||||
return "unknown platform";
|
||||
}
|
||||
|
||||
const char* get_arch() {
|
||||
if (is_x86()) {
|
||||
return "x86";
|
||||
} else if (is_x86_64()) {
|
||||
return "x86-64";
|
||||
} else if (is_amd64()) {
|
||||
return "amd64";
|
||||
} else if (is_arm()) {
|
||||
return "arm";
|
||||
} else if (is_aarch64()) {
|
||||
return "aarch64";
|
||||
} else if (is_ia64()) {
|
||||
return "ia64";
|
||||
} else if (is_powerpc()) {
|
||||
return "powerpc";
|
||||
} else if (is_superh()) {
|
||||
return "superh";
|
||||
}
|
||||
return "unknown arch";
|
||||
}
|
||||
|
||||
f64 hex_to_f64(const char* str) {
|
||||
f64 ret = 0;
|
||||
for(; *str; ++str) {
|
||||
|
|
|
@ -45,6 +45,9 @@ protected:
|
|||
bool first_exec_flag = true;
|
||||
bool allow_repl_output = false;
|
||||
|
||||
/* limited mode, will not load unsafe system api if switch on */
|
||||
bool flag_limited_mode = false;
|
||||
|
||||
/* vm initializing function */
|
||||
void init(
|
||||
const std::vector<std::string>&,
|
||||
|
@ -192,6 +195,8 @@ public:
|
|||
void set_repl_mode_flag(bool flag) {is_repl_mode = flag;}
|
||||
/* set repl output flag */
|
||||
void set_allow_repl_output_flag(bool flag) {allow_repl_output = flag;}
|
||||
/* set limit mode flag */
|
||||
void set_limit_mode_flag(bool flag) {flag_limited_mode = flag;}
|
||||
};
|
||||
|
||||
inline bool vm::cond(var& val) {
|
||||
|
|
|
@ -92,12 +92,12 @@ bool repl::run() {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (nasal_linker->link(*nasal_parser, "<nasal-repl>", true).geterr()) {
|
||||
if (nasal_linker->link(*nasal_parser, true).geterr()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nasal_opt->do_optimization(nasal_parser->tree());
|
||||
if (nasal_codegen->compile(*nasal_parser, *nasal_linker, true).geterr()) {
|
||||
if (nasal_codegen->compile(*nasal_parser, *nasal_linker, true, false).geterr()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ void repl::execute() {
|
|||
std::cout << "[nasal-repl] Initialization complete.\n\n";
|
||||
|
||||
// finish initialization, output version info
|
||||
std::cout << "Nasal REPL interpreter version " << __nasver;
|
||||
std::cout << "Nasal REPL interpreter version " << __nasver__;
|
||||
std::cout << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||
help();
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
use std.unix;
|
||||
|
||||
srand();
|
||||
|
||||
var ant = {
|
||||
new: func(color, pos_x, pos_y) {
|
||||
return {
|
||||
move: int(rand()*4),
|
||||
color: color,
|
||||
pos_x: pos_x,
|
||||
pos_y: pos_y
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
# generate agents
|
||||
var ants = [
|
||||
ant.new(10, 30, 15),
|
||||
ant.new(11, 31, 16),
|
||||
ant.new(4, 29, 13),
|
||||
ant.new(9, 30, 14),
|
||||
ant.new(13, 30, 12),
|
||||
ant.new(99, 25, 18)
|
||||
];
|
||||
|
||||
# initialize game map
|
||||
var map = [];
|
||||
var map_color = [];
|
||||
setsize(map, 60*30);
|
||||
setsize(map_color, 60*30);
|
||||
forindex(var i; map) {
|
||||
map[i] = 0;
|
||||
map_color[i] = 0;
|
||||
}
|
||||
foreach(var a; ants) {
|
||||
map_color[a.pos_x + a.pos_y*60] = a.color;
|
||||
}
|
||||
|
||||
var print_map = func {
|
||||
var res = "\e[1;1H";
|
||||
for(var y = 0; y<30; y += 1) {
|
||||
for(var x = 0; x<60; x += 1) {
|
||||
res ~= "\e[38;5;"~map_color[x + y*60]~";1m";
|
||||
res ~= map[x + y*60] ~ " \e[0m";
|
||||
}
|
||||
res ~= "\n";
|
||||
}
|
||||
print(res);
|
||||
}
|
||||
|
||||
var move = func {
|
||||
var move_step = [
|
||||
[0, -1],
|
||||
[1, 0],
|
||||
[0, 1],
|
||||
[-1, 0]
|
||||
];
|
||||
var temp_map = [];
|
||||
setsize(temp_map, 60*30);
|
||||
forindex(var i; map) {
|
||||
temp_map[i] = map[i];
|
||||
}
|
||||
foreach(var a; ants) {
|
||||
var map_state = map[a.pos_x + a.pos_y*60];
|
||||
temp_map[a.pos_x + a.pos_y*60] = map_state==0? 1:0;
|
||||
if (map_state==1) {
|
||||
a.move -= 1;
|
||||
if (a.move < 0) {
|
||||
a.move = 3;
|
||||
}
|
||||
} else {
|
||||
a.move += 1;
|
||||
if (a.move > 3) {
|
||||
a.move = 0;
|
||||
}
|
||||
}
|
||||
a.pos_x += move_step[a.move][0];
|
||||
a.pos_y += move_step[a.move][1];
|
||||
if (a.pos_x < 0) { a.pos_x = 59; }
|
||||
if (a.pos_x > 59) { a.pos_x = 0; }
|
||||
if (a.pos_y < 0) { a.pos_y = 29; }
|
||||
if (a.pos_y > 29) { a.pos_y = 0; }
|
||||
|
||||
if (map_color[a.pos_x + a.pos_y*60]!=a.color) {
|
||||
map_color[a.pos_x + a.pos_y*60] = a.color;
|
||||
} else {
|
||||
map_color[a.pos_x + a.pos_y*60] = 0;
|
||||
}
|
||||
}
|
||||
map = temp_map;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
print_map();
|
||||
move();
|
||||
unix.sleep(1/24);
|
||||
}
|
Loading…
Reference in New Issue