diff --git a/README.md b/README.md index d8b7a06..740163d 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,9 @@ __CAUTION__: If want to use the release zip/tar.gz file to build the interpreter Make sure your MinGW thread model is `posix thread model`, otherwise it may not have the thread library. -> mingw32-make nasal.exe +> mkdir build +> +> mingw32-make nasal.exe -j4 ### __`Windows (Visual Studio)`__ @@ -79,16 +81,14 @@ This project gives a [__CMakelists.txt__](./CMakeLists.txt) for you to create pr ### __`Linux/macOS/Unix`__ -> make nasal +> mkdir build +> +> make -j4 You could choose which compiler you want to use: > make nasal CXX=... -If you think `-O3` isn't that safe and stable, you could choose: - -> make stable-release - ## __How to Use__ ![usage](./doc/gif/help.gif) diff --git a/doc/README_zh.md b/doc/README_zh.md index 7c02eb2..a721005 100644 --- a/doc/README_zh.md +++ b/doc/README_zh.md @@ -62,7 +62,9 @@ __注意__: 如果你想直接下载发行版提供的zip/tar.gz压缩包来构 一定要确保您的 MinGW thread model 是 `posix thread model`, 否则可能存在没有 thread 库的问题。 -> mingw32-make nasal.exe +> mkdir build +> +> mingw32-make nasal.exe -j4 ### __`Windows` 平台(`Vistual Studio`)__ @@ -70,16 +72,14 @@ __注意__: 如果你想直接下载发行版提供的zip/tar.gz压缩包来构 ### __`Linux/macOS/Unix` 平台__ -> make nasal +> mkdir build +> +> make -j4 你也可以通过如下的其中一行命令来指定你想要使用的编译器: > make nasal CXX=... -如果你觉得`-O3`编译的版本不是那么安全和稳定,你也可以选择生成稳定的版本: - -> make stable-release - ## __使用方法__ ![usage](../doc/gif/help.gif) diff --git a/makefile b/makefile index 6aeac4a..0fbaaad 100644 --- a/makefile +++ b/makefile @@ -1,81 +1,84 @@ STD=c++17 NASAL_OBJECT=\ - nasal_err.o\ - nasal_ast.o\ - ast_visitor.o\ - ast_dumper.o\ - nasal_lexer.o\ - nasal_parse.o\ - nasal_import.o\ - optimizer.o\ - nasal_opcode.o\ - symbol_finder.o\ - nasal_codegen.o\ - nasal_misc.o\ - nasal_gc.o\ - nasal_builtin.o\ - nasal_vm.o\ - nasal_dbg.o\ - main.o + build/nasal_err.o\ + build/nasal_ast.o\ + build/ast_visitor.o\ + build/ast_dumper.o\ + build/nasal_lexer.o\ + build/nasal_parse.o\ + build/nasal_import.o\ + build/optimizer.o\ + build/nasal_opcode.o\ + build/symbol_finder.o\ + build/nasal_codegen.o\ + build/nasal_misc.o\ + build/nasal_gc.o\ + build/nasal_builtin.o\ + build/nasal_vm.o\ + build/nasal_dbg.o\ + build/main.o # for test -nasal: $(NASAL_OBJECT) +nasal: $(NASAL_OBJECT) | build $(CXX) $(NASAL_OBJECT) -O3 -o nasal -ldl -nasal.exe: $(NASAL_OBJECT) +nasal.exe: $(NASAL_OBJECT) | build $(CXX) $(NASAL_OBJECT) -O3 -o nasal.exe -main.o: src/main.cpp - $(CXX) -std=$(STD) -c -O3 src/main.cpp -fno-exceptions -fPIC -o main.o -I . +build: + @ if [ ! -d build ]; then mkdir build; fi -nasal_misc.o: src/nasal.h src/nasal_misc.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_misc.cpp -fno-exceptions -fPIC -o nasal_misc.o -I . +build/main.o: src/nasal.h src/nasal_err.h src/nasal_lexer.h src/main.cpp | build + $(CXX) -std=$(STD) -c -O3 src/main.cpp -fno-exceptions -fPIC -o build/main.o -I . -nasal_err.o: src/nasal_err.h src/nasal_err.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_err.cpp -fno-exceptions -fPIC -o nasal_err.o -I . +build/nasal_misc.o: src/nasal.h src/nasal_misc.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_misc.cpp -fno-exceptions -fPIC -o build/nasal_misc.o -I . -nasal_gc.o: src/nasal_gc.h src/nasal_gc.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_gc.cpp -fno-exceptions -fPIC -o nasal_gc.o -I . +build/nasal_err.o: src/nasal_err.h src/nasal_err.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_err.cpp -fno-exceptions -fPIC -o build/nasal_err.o -I . -nasal_import.o: src/nasal_import.h src/nasal_import.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_import.cpp -fno-exceptions -fPIC -o nasal_import.o -I . +build/nasal_gc.o: src/nasal_gc.h src/nasal_gc.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_gc.cpp -fno-exceptions -fPIC -o build/nasal_gc.o -I . -nasal_lexer.o: src/nasal_lexer.h src/nasal_lexer.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_lexer.cpp -fno-exceptions -fPIC -o nasal_lexer.o -I . +build/nasal_import.o: src/nasal_import.h src/nasal_import.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_import.cpp -fno-exceptions -fPIC -o build/nasal_import.o -I . -nasal_ast.o: src/nasal_ast.h src/nasal_ast.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_ast.cpp -fno-exceptions -fPIC -o nasal_ast.o -I . +build/nasal_lexer.o: src/nasal_lexer.h src/nasal_lexer.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_lexer.cpp -fno-exceptions -fPIC -o build/nasal_lexer.o -I . -nasal_builtin.o: src/nasal_builtin.h src/nasal_builtin.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_builtin.cpp -fno-exceptions -fPIC -o nasal_builtin.o -I . +build/nasal_ast.o: src/nasal_ast.h src/nasal_ast.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_ast.cpp -fno-exceptions -fPIC -o build/nasal_ast.o -I . -nasal_codegen.o: src/nasal_codegen.h src/nasal_codegen.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_codegen.cpp -fno-exceptions -fPIC -o nasal_codegen.o -I . +build/nasal_builtin.o: src/nasal_builtin.h src/nasal_builtin.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_builtin.cpp -fno-exceptions -fPIC -o build/nasal_builtin.o -I . -nasal_opcode.o: src/nasal_opcode.h src/nasal_opcode.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_opcode.cpp -fno-exceptions -fPIC -o nasal_opcode.o -I . +build/nasal_codegen.o: src/nasal_codegen.h src/nasal_codegen.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_codegen.cpp -fno-exceptions -fPIC -o build/nasal_codegen.o -I . -nasal_parse.o: src/nasal_parse.h src/nasal_parse.cpp src/nasal_ast.h - $(CXX) -std=$(STD) -c -O3 src/nasal_parse.cpp -fno-exceptions -fPIC -o nasal_parse.o -I . +build/nasal_opcode.o: src/nasal_opcode.h src/nasal_opcode.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_opcode.cpp -fno-exceptions -fPIC -o build/nasal_opcode.o -I . -optimizer.o: src/optimizer.h src/optimizer.cpp src/nasal_ast.h - $(CXX) -std=$(STD) -c -O3 src/optimizer.cpp -fno-exceptions -fPIC -o optimizer.o -I . +build/nasal_parse.o: src/nasal_parse.h src/nasal_parse.cpp src/nasal_ast.h | build + $(CXX) -std=$(STD) -c -O3 src/nasal_parse.cpp -fno-exceptions -fPIC -o build/nasal_parse.o -I . -symbol_finder.o: src/symbol_finder.h src/symbol_finder.cpp src/nasal_ast.h - $(CXX) -std=$(STD) -c -O3 src/symbol_finder.cpp -fno-exceptions -fPIC -o symbol_finder.o -I . +build/optimizer.o: src/optimizer.h src/optimizer.cpp src/nasal_ast.h | build + $(CXX) -std=$(STD) -c -O3 src/optimizer.cpp -fno-exceptions -fPIC -o build/optimizer.o -I . -ast_visitor.o: src/nasal_ast.h src/ast_visitor.h src/ast_visitor.cpp - $(CXX) -std=$(STD) -c -O3 src/ast_visitor.cpp -fno-exceptions -fPIC -o ast_visitor.o -I . +build/symbol_finder.o: src/symbol_finder.h src/symbol_finder.cpp src/nasal_ast.h | build + $(CXX) -std=$(STD) -c -O3 src/symbol_finder.cpp -fno-exceptions -fPIC -o build/symbol_finder.o -I . -ast_dumper.o: src/nasal_ast.h src/ast_visitor.h src/ast_dumper.h src/ast_dumper.cpp - $(CXX) -std=$(STD) -c -O3 src/ast_dumper.cpp -fno-exceptions -fPIC -o ast_dumper.o -I . +build/ast_visitor.o: src/nasal_ast.h src/ast_visitor.h src/ast_visitor.cpp | build + $(CXX) -std=$(STD) -c -O3 src/ast_visitor.cpp -fno-exceptions -fPIC -o build/ast_visitor.o -I . -nasal_vm.o: src/nasal_vm.h src/nasal_vm.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_vm.cpp -fno-exceptions -fPIC -o nasal_vm.o -I . +build/ast_dumper.o: src/nasal_ast.h src/ast_visitor.h src/ast_dumper.h src/ast_dumper.cpp + $(CXX) -std=$(STD) -c -O3 src/ast_dumper.cpp -fno-exceptions -fPIC -o build/ast_dumper.o -I . -nasal_dbg.o: src/nasal_dbg.h src/nasal_dbg.cpp - $(CXX) -std=$(STD) -c -O3 src/nasal_dbg.cpp -fno-exceptions -fPIC -o nasal_dbg.o -I . +build/nasal_vm.o: src/nasal_vm.h src/nasal_vm.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_vm.cpp -fno-exceptions -fPIC -o build/nasal_vm.o -I . + +build/nasal_dbg.o: src/nasal_dbg.h src/nasal_dbg.cpp | build + $(CXX) -std=$(STD) -c -O3 src/nasal_dbg.cpp -fno-exceptions -fPIC -o build/nasal_dbg.o -I . .PHONY: clean clean: diff --git a/module/makefile b/module/makefile index 4e635b0..1e28906 100644 --- a/module/makefile +++ b/module/makefile @@ -4,7 +4,7 @@ dynamic_libs_so = libfib.so libkey.so libnasock.so libmat.so dynamic_libs_dll = libfib.dll libkey.dll libnasock.dll libmat.dll used_header = ../src/nasal.h ../src/nasal_gc.h -used_object = ../nasal_misc.o ../nasal_gc.o +used_object = ../build/nasal_misc.o ../build/nasal_gc.o STD=c++17 diff --git a/src/main.cpp b/src/main.cpp index 3fddb4e..7d9b8fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -135,7 +135,7 @@ void execute( } // run - auto start=clk::now(); + auto start = clk::now(); if (cmd&VM_DEBUG) { dbg(err).run(gen, ld, argv); } else if (cmd&VM_TIME || cmd&VM_EXEC) { @@ -144,7 +144,7 @@ void execute( // get running time if (cmd&VM_TIME) { - f64 tm=(clk::now()-start).count()*1.0/den; + f64 tm = (clk::now()-start).count()*1.0/den; std::clog << "process exited after " << tm << "s.\n\n"; } } diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 35d03da..b7c0ca8 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -7,7 +7,7 @@ #include enum class expr_type:u32 { - ast_null=0, // null node + ast_null = 0, // null node ast_file_info, // stores file info ast_block, // code block ast_nil, // nil keyword @@ -25,9 +25,9 @@ enum class expr_type:u32 { ast_callf, // id() ast_subvec, // id[index:index] ast_param, // function parameter - ast_ternary, - ast_binary, - ast_unary, + ast_ternary, // ternary operator + ast_binary, // binary operator + ast_unary, // unary operator ast_for, // for keyword ast_forei, // foreach or forindex loop ast_while, // while @@ -35,10 +35,10 @@ enum class expr_type:u32 { ast_cond, // mark a sub-tree of conditional expression ast_if, // if keyword ast_multi_id, // multi identifiers sub-tree - ast_tuple, + ast_tuple, // tuple, stores multiple scalars ast_def, // definition - ast_assign, - ast_multi_assign, + ast_assign, // assignment + ast_multi_assign,// multiple assignment ast_continue, // continue keyword, only used in loop ast_break, // break keyword, only used in loop ast_ret // return keyword, only used in function block diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 93eb303..3f0326f 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -1,18 +1,18 @@ #include "nasal_builtin.h" var builtin_print(var* local, gc& ngc) { - for(auto& i:local[1].vec().elems) { - std::cout<1 || !end.str().length()) { - std::cin>>ret.str(); + std::cin >> ret.str(); } else { std::getline(std::cin, ret.str(), end.str()[0]); } @@ -72,21 +72,21 @@ var builtin_input(var* local, gc& ngc) { } var builtin_readfile(var* local, gc& ngc) { - var val=local[1]; + var val = local[1]; if (val.type!=vm_str) { return nas_err("io::readfile", "\"filename\" must be string"); } std::ifstream in(val.str(), std::ios::binary); std::stringstream rd; if (!in.fail()) { - rd<"); } - out<last) { vec.push_back(ngc.newstr(s.substr(last, pos-last))); } - last=pos+deli.length(); - pos=s.find(deli, last); + last = pos+deli.length(); + pos = s.find(deli, last); } if (last!=s.length()) { vec.push_back(ngc.newstr(s.substr(last))); } - ngc.temp=nil; + ngc.temp = nil; return res; } var builtin_rand(var* local, gc& ngc) { - var val=local[1]; + var val = local[1]; if (val.type!=vm_num && val.type!=vm_nil) { return nas_err("rand", "\"seed\" must be nil or number"); } @@ -146,25 +146,25 @@ var builtin_rand(var* local, gc& ngc) { srand((u32)val.num()); return nil; } - f64 num=0; - for(u32 i=0;i<5;++i) { - num=(num+rand())*(1.0/(RAND_MAX+1.0)); + f64 num = 0; + for(u32 i = 0; i<5; ++i) { + num = (num+rand())*(1.0/(RAND_MAX+1.0)); } return var::num(num); } var builtin_id(var* local, gc& ngc) { - var val=local[1]; + var val = local[1]; std::stringstream ss; - ss<<"0"; + ss << "0"; if (val.type>vm_num) { - ss<<"x"<= 0"); } - usize begin=(usize)beg.num(); - usize length=(usize)len.num(); + usize begin = (usize)beg.num(); + usize length = (usize)len.num(); if (begin>=str.str().length()) { return nas_err("susbtr", "begin index out of range: "+std::to_string(begin)); } @@ -405,14 +406,14 @@ var builtin_substr(var* local, gc& ngc) { } var builtin_streq(var* local, gc& ngc) { - var a=local[1]; - var b=local[2]; - return var::num(f64((a.type!=vm_str || b.type!=vm_str)?0:(a.str()==b.str()))); + var a = local[1]; + var b = local[2]; + return var::num(f64((a.type!=vm_str || b.type!=vm_str)? 0:(a.str()==b.str()))); } var builtin_left(var* local, gc& ngc) { - var str=local[1]; - var len=local[2]; + var str = local[1]; + var len = local[2]; if (str.type!=vm_str) { return nas_err("left", "\"string\" must be string"); } @@ -422,32 +423,32 @@ var builtin_left(var* local, gc& ngc) { if (len.num()<0) { return ngc.newstr(""); } - return ngc.newstr(str.str().substr(0,len.num())); + return ngc.newstr(str.str().substr(0, len.num())); } var builtin_right(var* local, gc& ngc) { - var str=local[1]; - var len=local[2]; + var str = local[1]; + var len = local[2]; if (str.type!=vm_str) { return nas_err("right", "\"string\" must be string"); } if (len.type!=vm_num) { return nas_err("right", "\"length\" must be number"); } - i32 length=(i32)len.num(); - i32 srclen=str.str().length(); + i32 length = (i32)len.num(); + i32 srclen = str.str().length(); if (length>srclen) { - length=srclen; + length = srclen; } if (length<0) { - length=0; + length = 0; } return ngc.newstr(str.str().substr(srclen-length, srclen)); } var builtin_cmp(var* local, gc& ngc) { - var a=local[1]; - var b=local[2]; + var a = local[1]; + var b = local[2]; if (a.type!=vm_str || b.type!=vm_str) { return nas_err("cmp", "\"a\" and \"b\" must be string"); } @@ -455,7 +456,7 @@ var builtin_cmp(var* local, gc& ngc) { } var builtin_chr(var* local, gc& ngc) { - const char* extend[]={ + const char* extend[] = { "€"," ","‚","ƒ","„","…","†","‡", "ˆ","‰","Š","‹","Œ"," ","Ž"," ", " ","‘","’","“","”","•","–","—", @@ -473,7 +474,7 @@ var builtin_chr(var* local, gc& ngc) { "ð","ñ","ò","ó","ô","õ","ö","÷", "ø","ù","ú","û","ü","ý","þ","ÿ" }; - i32 num=local[1].num(); + i32 num = local[1].num(); if (0<=num && num<128) { return ngc.newstr((char)num); } else if (128<=num && num<256) { @@ -487,13 +488,13 @@ var builtin_char(var* local, gc& ngc) { } var builtin_values(var* local, gc& ngc) { - var hash=local[1]; + var hash = local[1]; if (hash.type!=vm_hash) { return nas_err("values", "\"hash\" must be hash"); } - var vec=ngc.alloc(vm_vec); - auto& v=vec.vec().elems; - for(auto& i:hash.hash().elems) { + var vec = ngc.alloc(vm_vec); + auto& v = vec.vec().elems; + for(auto& i : hash.hash().elems) { v.push_back(i.second); } return vec; @@ -507,25 +508,25 @@ var builtin_exists(var* local, gc& ngc) { } var builtin_open(var* local, gc& ngc) { - var name=local[1]; - var mode=local[2]; + var name = local[1]; + var mode = local[2]; if (name.type!=vm_str) { return nas_err("open", "\"filename\" must be string"); } if (mode.type!=vm_str) { return nas_err("open", "\"mode\" must be string"); } - FILE* res=fopen(name.str().c_str(), mode.str().c_str()); + FILE* res = fopen(name.str().c_str(), mode.str().c_str()); if (!res) { return nas_err("open", "failed to open file <"+name.str()+">"); } - var ret=ngc.alloc(vm_obj); + var ret = ngc.alloc(vm_obj); ret.obj().set(ngc.global_ghost_type_table.ghost_file, res, &ngc.global_ghost_type_table); return ret; } var builtin_close(var* local, gc& ngc) { - var fd=local[1]; + var fd = local[1]; if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) { return nas_err("close", "not a valid filehandle"); } @@ -534,9 +535,9 @@ var builtin_close(var* local, gc& ngc) { } var builtin_read(var* local, gc& ngc) { - var fd=local[1]; - var buf=local[2]; - var len=local[3]; + var fd = local[1]; + var buf = local[2]; + var len = local[3]; if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) { return nas_err("read", "not a valid filehandle"); } @@ -549,20 +550,20 @@ var builtin_read(var* local, gc& ngc) { if (len.num()<=0 || len.num()>=(1<<30)) { return nas_err("read", "\"len\" less than 1 or too large"); } - char* buff=new char[(usize)len.num()+1]; + char* buff = new char[(usize)len.num()+1]; if (!buff) { return nas_err("read", "malloc failed"); } - f64 res=fread(buff,1,len.num(), (FILE*)fd.obj().ptr); - buf.str()=buff; - buf.val.gcobj->unmut=true; + f64 res = fread(buff,1,len.num(), (FILE*)fd.obj().ptr); + buf.str() = buff; + buf.val.gcobj->unmut = true; delete []buff; return var::num(res); } var builtin_write(var* local, gc& ngc) { - var fd=local[1]; - var str=local[2]; + var fd = local[1]; + var str = local[2]; if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) { return nas_err("write", "not a valid filehandle"); } @@ -573,9 +574,9 @@ var builtin_write(var* local, gc& ngc) { } var builtin_seek(var* local, gc& ngc) { - var fd=local[1]; - var pos=local[2]; - var whence=local[3]; + var fd = local[1]; + var pos = local[2]; + var whence = local[3]; if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) { return nas_err("seek", "not a valid filehandle"); } @@ -583,7 +584,7 @@ var builtin_seek(var* local, gc& ngc) { } var builtin_tell(var* local, gc& ngc) { - var fd=local[1]; + var fd = local[1]; if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) { return nas_err("tell", "not a valid filehandle"); } @@ -591,20 +592,20 @@ var builtin_tell(var* local, gc& ngc) { } var builtin_readln(var* local, gc& ngc) { - var fd=local[1]; + var fd = local[1]; if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) { return nas_err("readln", "not a valid filehandle"); } - var str=ngc.alloc(vm_str); + var str = ngc.alloc(vm_str); char c; - while((c=fgetc((FILE*)fd.obj().ptr))!=EOF) { + while((c = fgetc((FILE*)fd.obj().ptr))!=EOF) { if (c=='\r') { continue; } if (c=='\n') { return str; } - str.str()+=c; + str.str() += c; } if (str.str().length()) { return str; @@ -613,7 +614,7 @@ var builtin_readln(var* local, gc& ngc) { } var builtin_stat(var* local, gc& ngc) { - var name=local[1]; + var name = local[1]; if (name.type!=vm_str) { return nas_err("stat", "\"filename\" must be string"); } @@ -621,8 +622,8 @@ var builtin_stat(var* local, gc& ngc) { if (stat(name.str().c_str(),&buf)<0) { return nas_err("stat", "failed to open file <"+name.str()+">"); } - var ret=ngc.alloc(vm_vec); - ret.vec().elems={ + var ret = ngc.alloc(vm_vec); + ret.vec().elems = { var::num((f64)buf.st_dev), var::num((f64)buf.st_ino), var::num((f64)buf.st_mode), @@ -639,7 +640,7 @@ var builtin_stat(var* local, gc& ngc) { } var builtin_eof(var* local, gc& ngc) { - var fd=local[1]; + var fd = local[1]; if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) { return nas_err("readln", "not a valid filehandle"); } @@ -650,25 +651,25 @@ var builtin_fld(var* local, gc& ngc) { // bits.fld(s,0,3); // if s stores 10100010(162) // will get 101(5) - var str=local[1]; - var startbit=local[2]; - var length=local[3]; + var str = local[1]; + var startbit = local[2]; + var length = local[3]; if (str.type!=vm_str || str.val.gcobj->unmut) { return nas_err("fld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num) { return nas_err("fld", "\"startbit\",\"len\" must be number"); } - u32 bit=(u32)startbit.num(); - u32 len=(u32)length.num(); + u32 bit = (u32)startbit.num(); + u32 len = (u32)length.num(); if (bit+len>8*str.str().length()) { return nas_err("fld", "bitfield out of bounds"); } - u32 res=0; - auto& s=str.str(); - for(u32 i=bit;i>3]&(1<<(7-(i&7)))) { - res|=1<<(bit+len-i-1); + res |= 1<<(bit+len-i-1); } } return var::num((f64)res); @@ -679,29 +680,29 @@ var builtin_sfld(var* local, gc& ngc) { // if s stores 10100010(162) // will get 101(5) then this will be signed extended to // 11111101(-3) - var str=local[1]; - var startbit=local[2]; - var length=local[3]; + var str = local[1]; + var startbit = local[2]; + var length = local[3]; if (str.type!=vm_str || str.val.gcobj->unmut) { return nas_err("sfld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num) { return nas_err("sfld", "\"startbit\",\"len\" must be number"); } - u32 bit=(u32)startbit.num(); - u32 len=(u32)length.num(); + u32 bit = (u32)startbit.num(); + u32 len = (u32)length.num(); if (bit+len>8*str.str().length()) { return nas_err("sfld", "bitfield out of bounds"); } - u32 res=0; - auto& s=str.str(); - for(u32 i=bit;i>3]&(1<<(7-(i&7)))) { - res|=1<<(bit+len-i-1); + res |= 1<<(bit+len-i-1); } } if (res&(1<<(len-1))) { - res|=~((1<unmut) { return nas_err("setfld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num || value.type!=vm_num) { return nas_err("setfld", "\"startbit\",\"len\",\"val\" must be number"); } - u32 bit=(u32)startbit.num(); - u32 len=(u32)length.num(); - u64 val=(u64)value.num(); + u32 bit = (u32)startbit.num(); + u32 len = (u32)length.num(); + u64 val = (u64)value.num(); if (bit+len>8*str.str().length()) { return nas_err("setfld", "bitfield out of bounds"); } - auto& s=str.str(); - for(u32 i=bit;i>3]|=(1<<(7-(i&7))); + s[i>>3] |= (1<<(7-(i&7))); } else { - s[i>>3]&=~(1<<(7-(i&7))); + s[i>>3] &= ~(1<<(7-(i&7))); } } return nil; } var builtin_buf(var* local, gc& ngc) { - var length=local[1]; + var length = local[1]; if (length.type!=vm_num || length.num()<=0) { return nas_err("buf", "\"len\" must be number greater than 0"); } - var str=ngc.alloc(vm_str); - auto& s=str.str(); + var str = ngc.alloc(vm_str); + auto& s = str.str(); s.resize(length.num(), '\0'); return str; } var builtin_sleep(var* local, gc& ngc) { - var val=local[1]; + var val = local[1]; if (val.type!=vm_num) { return nil; } @@ -767,7 +768,7 @@ var builtin_sleep(var* local, gc& ngc) { var builtin_pipe(var* local, gc& ngc) { #ifndef _WIN32 i32 fd[2]; - var res=ngc.alloc(vm_vec); + var res = ngc.alloc(vm_vec); if (pipe(fd)==-1) { return nas_err("pipe", "failed to create pipe"); } @@ -790,15 +791,15 @@ var builtin_fork(var* local, gc& ngc) { } var builtin_waitpid(var* local, gc& ngc) { - var pid=local[1]; - var nohang=local[2]; + var pid = local[1]; + var nohang = local[2]; if (pid.type!=vm_num || nohang.type!=vm_num) { return nas_err("waitpid", "pid and nohang must be number"); } #ifndef _WIN32 i32 ret_pid,status; - ret_pid=waitpid(pid.num(),&status,nohang.num()==0?0:WNOHANG); - var vec=ngc.alloc(vm_vec); + ret_pid = waitpid(pid.num(),&status,nohang.num()==0? 0:WNOHANG); + var vec = ngc.alloc(vm_vec); vec.vec().elems.push_back(var::num((f64)ret_pid)); vec.vec().elems.push_back(var::num((f64)status)); return vec; @@ -807,30 +808,30 @@ var builtin_waitpid(var* local, gc& ngc) { } var builtin_opendir(var* local, gc& ngc) { - var path=local[1]; + var path = local[1]; if (path.type!=vm_str) { return nas_err("opendir", "\"path\" must be string"); } #ifdef _MSC_VER WIN32_FIND_DATAA data; HANDLE p; - p=FindFirstFileA((path.str()+"\\*.*").c_str(),&data); + p = FindFirstFileA((path.str()+"\\*.*").c_str(),&data); if (p==INVALID_HANDLE_VALUE) { return nas_err("opendir", "cannot open dir <"+path.str()+">"); } #else - DIR* p=opendir(path.str().c_str()); + DIR* p = opendir(path.str().c_str()); if (!p) { return nas_err("opendir", "cannot open dir <"+path.str()+">"); } #endif - var ret=ngc.alloc(vm_obj); + var ret = ngc.alloc(vm_obj); ret.obj().set(ngc.global_ghost_type_table.ghost_dir, p, &ngc.global_ghost_type_table); return ret; } var builtin_readdir(var* local, gc& ngc) { - var handle=local[1]; + var handle = local[1]; if (!handle.objchk(ngc.global_ghost_type_table.ghost_dir)) { return nas_err("readdir", "not a valid dir handle"); } @@ -841,13 +842,13 @@ var builtin_readdir(var* local, gc& ngc) { } return ngc.newstr(data.cFileName); #else - dirent* p=readdir((DIR*)handle.obj().ptr); - return p?ngc.newstr(p->d_name):nil; + dirent* p = readdir((DIR*)handle.obj().ptr); + return p? ngc.newstr(p->d_name):nil; #endif } var builtin_closedir(var* local, gc& ngc) { - var handle=local[1]; + var handle = local[1]; if (!handle.objchk(ngc.global_ghost_type_table.ghost_dir)) { return nas_err("closedir", "not a valid dir handle"); } @@ -856,7 +857,7 @@ var builtin_closedir(var* local, gc& ngc) { } var builtin_chdir(var* local, gc& ngc) { - var path=local[1]; + var path = local[1]; if (path.type!=vm_str) { return var::num((f64)-1); } @@ -864,83 +865,83 @@ var builtin_chdir(var* local, gc& ngc) { } var builtin_environ(var* local, gc& ngc) { - var res=ngc.temp=ngc.alloc(vm_vec); - auto& vec=res.vec().elems; - for(char** env=environ;*env;++env) { + var res = ngc.temp = ngc.alloc(vm_vec); + auto& vec = res.vec().elems; + for(char** env = environ; *env; ++env) { vec.push_back(ngc.newstr(*env)); } - ngc.temp=nil; + ngc.temp = nil; return res; } var builtin_getcwd(var* local, gc& ngc) { char buf[1024]; - if (!getcwd(buf,sizeof(buf))) { + if (!getcwd(buf, sizeof(buf))) { return nil; } return ngc.newstr(buf); } var builtin_getenv(var* local, gc& ngc) { - var envvar=local[1]; + var envvar = local[1]; if (envvar.type!=vm_str) { return nas_err("getenv", "\"envvar\" must be string"); } - char* res=getenv(envvar.str().c_str()); - return res?ngc.newstr(res):nil; + char* res = getenv(envvar.str().c_str()); + return res? ngc.newstr(res):nil; } var builtin_dlopen(var* local, gc& ngc) { - var dlname=local[1]; + var dlname = local[1]; if (dlname.type!=vm_str) { return nas_err("dlopen", "\"libname\" must be string"); } #ifdef _WIN32 - wchar_t* str=new wchar_t[dlname.str().size()+1]; + wchar_t* str = new wchar_t[dlname.str().size()+1]; if (!str) { return nas_err("dlopen", "malloc failed"); } memset(str, 0, sizeof(wchar_t)*dlname.str().size()+1); mbstowcs(str, dlname.str().c_str(),dlname.str().size()+1); - void* ptr=LoadLibraryA(dlname.str().c_str()); + void* ptr = LoadLibraryA(dlname.str().c_str()); delete []str; #else - void* ptr=dlopen(dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY); + void* ptr = dlopen(dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY); #endif if (!ptr) { return nas_err("dlopen", "cannot open dynamic lib <"+dlname.str()+">"); } - var ret=ngc.temp=ngc.alloc(vm_hash); - var lib=ngc.alloc(vm_obj); + var ret = ngc.temp = ngc.alloc(vm_hash); + var lib = ngc.alloc(vm_obj); lib.obj().set(ngc.global_ghost_type_table.ghost_dylib, ptr, &ngc.global_ghost_type_table); - ret.hash().elems["lib"]=lib; + ret.hash().elems["lib"] = lib; #ifdef _WIN32 - void* func=(void*)GetProcAddress((HMODULE)lib.obj().ptr, "get"); + void* func = (void*)GetProcAddress((HMODULE)lib.obj().ptr, "get"); #else - void* func=dlsym(lib.obj().ptr, "get"); + void* func = dlsym(lib.obj().ptr, "get"); #endif if (!func) { return nas_err("dlopen", "cannot find function"); } // get function pointer by name - module_func_info* tbl=((get_func_ptr)func)(&ngc.global_ghost_type_table); + module_func_info* tbl = ((get_func_ptr)func)(&ngc.global_ghost_type_table); if (!tbl) { return nas_err("dlopen", "failed to get module functions"); } - for(u32 i=0;tbl[i].name;++i) { - void* p=(void*)tbl[i].fd; - var tmp=ngc.alloc(vm_obj); + for(u32 i = 0; tbl[i].name; ++i) { + void* p = (void*)tbl[i].fd; + var tmp = ngc.alloc(vm_obj); tmp.obj().set(ngc.global_ghost_type_table.ghost_faddr, p, &ngc.global_ghost_type_table); - ret.hash().elems[tbl[i].name]=tmp; + ret.hash().elems[tbl[i].name] = tmp; } - ngc.temp=nil; + ngc.temp = nil; return ret; } var builtin_dlclose(var* local, gc& ngc) { - var libptr=local[1]; + var libptr = local[1]; if (!libptr.objchk(ngc.global_ghost_type_table.ghost_dylib)) { return nas_err("dlclose", "\"lib\" is not a valid dynamic lib"); } @@ -949,33 +950,28 @@ var builtin_dlclose(var* local, gc& ngc) { } var builtin_dlcallv(var* local, gc& ngc) { - var fp=local[1]; - var args=local[2]; + var fp = local[1]; + var args = local[2]; if (!fp.objchk(ngc.global_ghost_type_table.ghost_faddr)) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } - auto& vec=args.vec().elems; - return ((module_func)fp.obj().ptr)( - vec.data(), - vec.size(), - &ngc - ); + auto& vec = args.vec().elems; + return ((module_func)fp.obj().ptr)(vec.data(), vec.size(), &ngc); } var builtin_dlcall(var* local, gc& ngc) { - var fp=local[1]; + var fp = local[1]; if (!fp.objchk(ngc.global_ghost_type_table.ghost_faddr)) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } - var* local_frame_start=local+2; - usize local_frame_size=ngc.rctx->top-local_frame_start; + var* local_frame_start = local+2; + usize local_frame_size = ngc.rctx->top-local_frame_start; // arguments' stored place begins at local +2 return ((module_func)fp.obj().ptr)( local_frame_start, local_frame_size, - &ngc - ); + &ngc); } var builtin_platform(var* local, gc& ngc) { @@ -1012,32 +1008,32 @@ var builtin_arch(var* local, gc& ngc) { // md5 related functions std::string tohex(u32 num) { - const char str16[]="0123456789abcdef"; - std::string str=""; - for(u32 i=0;i<4;i++, num>>=8) { - std::string tmp=""; - for(u32 j=0,b=num&0xff;j<2;j++,b>>=4) { - tmp.insert(0,1,str16[b&0xf]); + const char str16[] = "0123456789abcdef"; + std::string str = ""; + for(u32 i = 0; i<4; i++, num >>= 8) { + std::string tmp = ""; + for(u32 j = 0, b = num&0xff; j<2; j++, b >>= 4) { + tmp.insert(0, 1, str16[b&0xf]); } - str+=tmp; + str += tmp; } return str; } std::string md5(const std::string& src) { std::vector buff; - usize num=((src.length()+8)>>6)+1; - usize buffsize=num<<4; + usize num = ((src.length()+8)>>6)+1; + usize buffsize = num<<4; buff.resize(buffsize,0); - for(usize i=0;i>2]|=((u8)src[i])<<((i&0x3)<<3); + for(usize i = 0; i>2] |= ((u8)src[i])<<((i&0x3)<<3); } - buff[src.length()>>2]|=0x80<<(((src.length()%4))<<3); - buff[buffsize-2]=(src.length()<<3)&0xffffffff; - buff[buffsize-1]=((src.length()<<3)>>32)&0xffffffff; + buff[src.length()>>2] |= 0x80<<(((src.length()%4))<<3); + buff[buffsize-2] = (src.length()<<3)&0xffffffff; + buff[buffsize-1] = ((src.length()<<3)>>32)&0xffffffff; // u32(abs(sin(i+1))*(2pow32)) - const u32 k[]={ + const u32 k[] = { 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501, 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821, 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, @@ -1049,7 +1045,7 @@ std::string md5(const std::string& src) { }; // left shift bits - const u32 s[]={ + const u32 s[] = { 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22, 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, @@ -1057,7 +1053,7 @@ std::string md5(const std::string& src) { }; // index - const u32 idx[]={ + const u32 idx[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, // g=i 1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12, // g=(5*i+1)%16; 5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2, // g=(3*i+5)%16; @@ -1070,31 +1066,31 @@ std::string md5(const std::string& src) { #define md5h(x,y,z) ((x)^(y)^(z)) #define md5i(x,y,z) ((y)^((x)|(~z))) - u32 atmp=0x67452301,btmp=0xefcdab89; - u32 ctmp=0x98badcfe,dtmp=0x10325476; - for(u32 i=0;i + f64 res = std::chrono::duration_cast (std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); return var::num(res); } var builtin_sysargv(var* local, gc& ngc) { - var res=ngc.alloc(vm_vec); - res.vec().elems=ngc.env_argv; + var res = ngc.alloc(vm_vec); + res.vec().elems = ngc.env_argv; return res; } var builtin_gcextend(var* local, gc& ngc) { - var type=local[1]; + var type = local[1]; if (type.type!=vm_str) { return nil; } - auto& s=type.str(); + auto& s = type.str(); if (s=="str") { ngc.extend(vm_str); } else if (s=="vec") { @@ -1245,8 +1241,8 @@ var builtin_gcextend(var* local, gc& ngc) { } var builtin_logtime(var* local, gc& ngc) { - time_t t=time(nullptr); - tm* tm_t=localtime(&t); + time_t t = time(nullptr); + tm* tm_t = localtime(&t); char s[64]; snprintf( s,64,"%d-%.2d-%.2d %.2d:%.2d:%.2d", @@ -1273,96 +1269,96 @@ var builtin_ghosttype(var* local, gc& ngc) { } nasal_builtin_table builtin[] = { - {"__print", builtin_print }, - {"__println", builtin_println }, - {"__exit", builtin_exit }, - {"__abort", builtin_abort }, - {"__append", builtin_append }, - {"__setsize", builtin_setsize }, - {"__system", builtin_system }, - {"__input", builtin_input }, - {"__readfile",builtin_readfile}, - {"__fout", builtin_fout }, - {"__split", builtin_split }, - {"__rand", builtin_rand }, - {"__id", builtin_id }, - {"__int", builtin_int }, - {"__floor", builtin_floor }, - {"__num", builtin_num }, - {"__pop", builtin_pop }, - {"__str", builtin_str }, - {"__size", builtin_size }, - {"__u32xor", builtin_u32xor }, - {"__u32and", builtin_u32and }, - {"__u32or", builtin_u32or }, - {"__u32nand", builtin_u32nand }, - {"__u32not", builtin_u32not }, - {"__pow", builtin_pow }, - {"__sin", builtin_sin }, - {"__cos", builtin_cos }, - {"__tan", builtin_tan }, - {"__exp", builtin_exp }, - {"__lg", builtin_lg }, - {"__ln", builtin_ln }, - {"__sqrt", builtin_sqrt }, - {"__atan2", builtin_atan2 }, - {"__isnan", builtin_isnan }, - {"__time", builtin_time }, - {"__contains",builtin_contains}, - {"__delete", builtin_delete }, - {"__keys", builtin_keys }, - {"__die", builtin_die }, - {"__find", builtin_find }, - {"__type", builtin_type }, - {"__substr", builtin_substr }, - {"__streq", builtin_streq }, - {"__left", builtin_left }, - {"__right", builtin_right }, - {"__cmp", builtin_cmp }, - {"__chr", builtin_chr }, - {"__char", builtin_char }, - {"__values", builtin_values }, - {"__exists", builtin_exists }, - {"__open", builtin_open }, - {"__close", builtin_close }, - {"__read", builtin_read }, - {"__write", builtin_write }, - {"__seek", builtin_seek }, - {"__tell", builtin_tell }, - {"__readln", builtin_readln }, - {"__stat", builtin_stat }, - {"__eof", builtin_eof }, - {"__fld", builtin_fld }, - {"__sfld", builtin_sfld }, - {"__setfld", builtin_setfld }, - {"__buf", builtin_buf }, - {"__sleep", builtin_sleep }, - {"__pipe", builtin_pipe }, - {"__fork", builtin_fork }, - {"__waitpid", builtin_waitpid }, - {"__opendir", builtin_opendir }, - {"__readdir", builtin_readdir }, - {"__closedir",builtin_closedir}, - {"__chdir", builtin_chdir }, - {"__environ", builtin_environ }, - {"__getcwd", builtin_getcwd }, - {"__getenv", builtin_getenv }, - {"__dlopen", builtin_dlopen }, - {"__dlclose", builtin_dlclose }, - {"__dlcallv", builtin_dlcallv }, - {"__dlcall", builtin_dlcall }, - {"__platform",builtin_platform}, - {"__arch", builtin_arch }, - {"__md5", builtin_md5 }, - {"__cocreate",builtin_cocreate}, - {"__coresume",builtin_coresume}, + {"__print", builtin_print}, + {"__println", builtin_println}, + {"__exit", builtin_exit}, + {"__abort", builtin_abort}, + {"__append", builtin_append}, + {"__setsize", builtin_setsize}, + {"__system", builtin_system}, + {"__input", builtin_input}, + {"__readfile", builtin_readfile}, + {"__fout", builtin_fout}, + {"__split", builtin_split}, + {"__rand", builtin_rand}, + {"__id", builtin_id}, + {"__int", builtin_int}, + {"__floor", builtin_floor}, + {"__num", builtin_num}, + {"__pop", builtin_pop}, + {"__str", builtin_str}, + {"__size", builtin_size}, + {"__u32xor", builtin_u32xor}, + {"__u32and", builtin_u32and}, + {"__u32or", builtin_u32or}, + {"__u32nand", builtin_u32nand}, + {"__u32not", builtin_u32not}, + {"__pow", builtin_pow}, + {"__sin", builtin_sin}, + {"__cos", builtin_cos}, + {"__tan", builtin_tan}, + {"__exp", builtin_exp}, + {"__lg", builtin_lg}, + {"__ln", builtin_ln}, + {"__sqrt", builtin_sqrt}, + {"__atan2", builtin_atan2}, + {"__isnan", builtin_isnan}, + {"__time", builtin_time}, + {"__contains", builtin_contains}, + {"__delete", builtin_delete}, + {"__keys", builtin_keys}, + {"__die", builtin_die}, + {"__find", builtin_find}, + {"__type", builtin_type}, + {"__substr", builtin_substr}, + {"__streq", builtin_streq}, + {"__left", builtin_left}, + {"__right", builtin_right}, + {"__cmp", builtin_cmp}, + {"__chr", builtin_chr}, + {"__char", builtin_char}, + {"__values", builtin_values}, + {"__exists", builtin_exists}, + {"__open", builtin_open}, + {"__close", builtin_close}, + {"__read", builtin_read}, + {"__write", builtin_write}, + {"__seek", builtin_seek}, + {"__tell", builtin_tell}, + {"__readln", builtin_readln}, + {"__stat", builtin_stat}, + {"__eof", builtin_eof}, + {"__fld", builtin_fld}, + {"__sfld", builtin_sfld}, + {"__setfld", builtin_setfld}, + {"__buf", builtin_buf}, + {"__sleep", builtin_sleep}, + {"__pipe", builtin_pipe}, + {"__fork", builtin_fork}, + {"__waitpid", builtin_waitpid}, + {"__opendir", builtin_opendir}, + {"__readdir", builtin_readdir}, + {"__closedir", builtin_closedir}, + {"__chdir", builtin_chdir}, + {"__environ", builtin_environ}, + {"__getcwd", builtin_getcwd}, + {"__getenv", builtin_getenv}, + {"__dlopen", builtin_dlopen}, + {"__dlclose", builtin_dlclose}, + {"__dlcallv", builtin_dlcallv}, + {"__dlcall", builtin_dlcall}, + {"__platform", builtin_platform}, + {"__arch", builtin_arch}, + {"__md5", builtin_md5}, + {"__cocreate", builtin_cocreate}, + {"__coresume", builtin_coresume}, {"__coyield", builtin_coyield }, - {"__costatus",builtin_costatus}, - {"__corun" ,builtin_corun }, - {"__millisec",builtin_millisec}, - {"__sysargv", builtin_sysargv }, - {"__gcextd", builtin_gcextend}, - {"__logtime", builtin_logtime }, + {"__costatus", builtin_costatus}, + {"__corun", builtin_corun}, + {"__millisec", builtin_millisec}, + {"__sysargv", builtin_sysargv}, + {"__gcextd", builtin_gcextend}, + {"__logtime", builtin_logtime}, {"__ghosttype", builtin_ghosttype}, - {nullptr, nullptr } + {nullptr, nullptr} }; \ No newline at end of file diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index fee4dbb..f84c53e 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -1091,7 +1091,18 @@ const error& codegen::compile(parse& parse, linker& import) { fileindex = 0; file = import.filelist().data(); in_iterloop.push(0); + + // add special symbol globals, which is a hash stores all global variables add_symbol("globals"); + // add special symbol arg here, which is used to store function arguments + // for example: + // var f = func(a) {print(arg)} + // f(1, 2, 3); + // then the arg is [2, 3], because 1 is accepted by "a" + // so in fact "f" is the same as: + // var f = func(a, arg...) {return(arg)} + add_symbol("arg"); + find_symbol(parse.tree()); // search symbols first gen(op_intg, global.size(), 0); block_gen(parse.tree()); // generate main block diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 673d893..e4103e7 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -643,6 +643,12 @@ inline void vm::o_callfv() { for(u32 i=psize;i= `A` and mutable[i] <= `Z`) { + mutable[i] += (`a` - `A`); + } + } + return mutable; +} +print(ascii_lc("ABCDEFG"), "\n"); # prints "abcdefg" + +# +# Advanced vectors: The lookup index can be negative, where -1 +# indicates the last element in the vector (or string). +# +next_to_last = list1[-2]; + +# +# Remember that strings look syntactically like vectors of bytes; so +# conversely, the "~" concatenation operator works equally well to +# concatenate vectors: +# +joined_list = [1, 2, 3] ~ [4, 5, 6]; + +### +### Now some fun examples: +### + +# +# Make a "inverted index" hash out of a vector that returns the index +# for each element. +# +invert = func(vec) { + hash = {}; + for(i=0; i 0) { result = result ~ dump(o[0]); } + for(i=1; i 0) { + k = ks[0]; + result = result ~ k ~ ":" ~ dump(o[k]); + } + for(i=1; i