Merge pull request #24 from ValKmjolnir/develop
🐛 fix bug of argument "arg"
This commit is contained in:
commit
ea33a5ed81
28
README.md
28
README.md
|
@ -761,6 +761,8 @@ If get this, Congratulations!
|
|||
<details><summary>Must use `var` to define variables</summary>
|
||||
|
||||
This interpreter uses more strict syntax to make sure it is easier for you to program and debug.
|
||||
And flightgear's nasal interpreter also has the same rule.
|
||||
So do not use variable without using `var` to declare it.
|
||||
|
||||
In Andy's interpreter:
|
||||
|
||||
|
@ -794,32 +796,6 @@ code: undefined symbol "i"
|
|||
|
||||
</details>
|
||||
|
||||
<details><summary>Default dynamic arguments not supported</summary>
|
||||
|
||||
In this interpreter,
|
||||
function doesn't put dynamic args into vector `arg` by default.
|
||||
So if you use `arg` without definition,
|
||||
you'll get an error of `undefined symbol`.
|
||||
|
||||
```javascript
|
||||
var f=func(){
|
||||
println(arg)
|
||||
}
|
||||
f(1,2,3);
|
||||
```
|
||||
|
||||
Compilation result:
|
||||
|
||||
```javascript
|
||||
code: undefined symbol "arg"
|
||||
--> test.nas:2:15
|
||||
|
|
||||
2 | println(arg)
|
||||
| ^ undefined symbol "arg"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## __Trace Back Info__
|
||||
|
||||

|
||||
|
|
|
@ -735,6 +735,7 @@ dylib.dlclose(dlhandle.lib);
|
|||
<details><summary>必须用 var 定义变量</summary>
|
||||
|
||||
这个解释器使用了更加严格的语法检查来保证你可以更轻松地debug。这是非常有必要的严格,否则debug会非常痛苦。
|
||||
同样的,flightgear 内置的 nasal 解释器也采取了类似的措施,所以使用变量前务必用 `var` 先进行声明。
|
||||
|
||||
在Andy的解释器中:
|
||||
|
||||
|
@ -762,29 +763,6 @@ code: undefined symbol "i"
|
|||
```
|
||||
</details>
|
||||
|
||||
<details><summary>默认不定长参数</summary>
|
||||
|
||||
这个解释器在运行时,函数不会将超出参数表的那部分不定长参数放到默认的`arg`中。所以你如果不定义`arg`就使用它,那你只会得到`undefined symbol`。
|
||||
|
||||
```javascript
|
||||
var f=func(){
|
||||
println(arg)
|
||||
}
|
||||
f(1,2,3);
|
||||
```
|
||||
|
||||
编译结果:
|
||||
|
||||
```javascript
|
||||
code: undefined symbol "arg"
|
||||
--> test.nas:2:15
|
||||
|
|
||||
2 | println(arg)
|
||||
| ^ undefined symbol "arg"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## __堆栈追踪信息__
|
||||
|
||||

|
||||
|
|
91
makefile
91
makefile
|
@ -1,5 +1,23 @@
|
|||
STD=c++17
|
||||
|
||||
NASAL_HEADER=\
|
||||
src/ast_dumper.h\
|
||||
src/ast_visitor.h\
|
||||
src/nasal_ast.h\
|
||||
src/nasal_builtin.h\
|
||||
src/nasal_codegen.h\
|
||||
src/nasal_dbg.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_gc.h\
|
||||
src/nasal_import.h\
|
||||
src/nasal_lexer.h\
|
||||
src/nasal_opcode.h\
|
||||
src/nasal_parse.h\
|
||||
src/nasal_vm.h\
|
||||
src/nasal.h\
|
||||
src/optimizer.h\
|
||||
src/symbol_finder.h
|
||||
|
||||
NASAL_OBJECT=\
|
||||
build/nasal_err.o\
|
||||
build/nasal_ast.o\
|
||||
|
@ -29,55 +47,96 @@ nasal.exe: $(NASAL_OBJECT) | build
|
|||
build:
|
||||
@ if [ ! -d build ]; then mkdir build; fi
|
||||
|
||||
build/main.o: src/nasal.h src/nasal_err.h src/nasal_lexer.h src/main.cpp | build
|
||||
build/main.o: $(NASAL_HEADER) src/main.cpp | build
|
||||
$(CXX) -std=$(STD) -c -O3 src/main.cpp -fno-exceptions -fPIC -o build/main.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 .
|
||||
|
||||
build/nasal_err.o: src/nasal_err.h src/nasal_err.cpp | build
|
||||
build/nasal_err.o: src/nasal.h src/nasal_err.h src/nasal_err.cpp | build
|
||||
$(CXX) -std=$(STD) -c -O3 src/nasal_err.cpp -fno-exceptions -fPIC -o build/nasal_err.o -I .
|
||||
|
||||
build/nasal_gc.o: src/nasal_gc.h src/nasal_gc.cpp | build
|
||||
build/nasal_gc.o: src/nasal.h 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 .
|
||||
|
||||
build/nasal_import.o: src/nasal_import.h src/nasal_import.cpp | build
|
||||
build/nasal_import.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_ast.h\
|
||||
src/nasal_lexer.h\
|
||||
src/nasal_parse.h\
|
||||
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 .
|
||||
|
||||
build/nasal_lexer.o: src/nasal_lexer.h src/nasal_lexer.cpp | build
|
||||
build/nasal_lexer.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
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 .
|
||||
|
||||
build/nasal_ast.o: src/nasal_ast.h src/nasal_ast.cpp | build
|
||||
build/nasal_ast.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
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 .
|
||||
|
||||
build/nasal_builtin.o: src/nasal_builtin.h src/nasal_builtin.cpp | build
|
||||
build/nasal_builtin.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_gc.h\
|
||||
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 .
|
||||
|
||||
build/nasal_codegen.o: src/nasal_codegen.h src/nasal_codegen.cpp | build
|
||||
build/nasal_codegen.o: $(NASAL_HEADER) 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 .
|
||||
|
||||
build/nasal_opcode.o: src/nasal_opcode.h src/nasal_opcode.cpp | build
|
||||
build/nasal_opcode.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_builtin.h\
|
||||
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 .
|
||||
|
||||
build/nasal_parse.o: src/nasal_parse.h src/nasal_parse.cpp src/nasal_ast.h | build
|
||||
build/nasal_parse.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_ast.h\
|
||||
src/nasal_lexer.h\
|
||||
src/nasal_err.h\
|
||||
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 .
|
||||
|
||||
build/optimizer.o: src/optimizer.h src/optimizer.cpp src/nasal_ast.h | build
|
||||
build/optimizer.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h\
|
||||
src/ast_visitor.h\
|
||||
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 .
|
||||
|
||||
build/symbol_finder.o: src/symbol_finder.h src/symbol_finder.cpp src/nasal_ast.h | build
|
||||
build/symbol_finder.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h\
|
||||
src/ast_visitor.h\
|
||||
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 .
|
||||
|
||||
build/ast_visitor.o: src/nasal_ast.h src/ast_visitor.h src/ast_visitor.cpp | build
|
||||
build/ast_visitor.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
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 .
|
||||
|
||||
build/ast_dumper.o: src/nasal_ast.h src/ast_visitor.h src/ast_dumper.h src/ast_dumper.cpp
|
||||
build/ast_dumper.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h\
|
||||
src/ast_visitor.h\
|
||||
src/ast_dumper.h src/ast_dumper.cpp | build
|
||||
$(CXX) -std=$(STD) -c -O3 src/ast_dumper.cpp -fno-exceptions -fPIC -o build/ast_dumper.o -I .
|
||||
|
||||
build/nasal_vm.o: src/nasal_vm.h src/nasal_vm.cpp | build
|
||||
build/nasal_vm.o: $(NASAL_HEADER) 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
|
||||
build/nasal_dbg.o: $(NASAL_HEADER) 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
|
||||
|
|
|
@ -16,7 +16,7 @@ var fib(var* args, usize size, gc* ngc) {
|
|||
if (!size) {
|
||||
return nas_err("fib","lack arguments");
|
||||
}
|
||||
var num=args[0];
|
||||
var num = args[0];
|
||||
return var::num(fibonaci(num.tonum()));
|
||||
}
|
||||
|
||||
|
@ -24,15 +24,15 @@ var quick_fib(var* args, usize size, gc* ngc) {
|
|||
if (!size) {
|
||||
return nas_err("quick_fib","lack arguments");
|
||||
}
|
||||
double num=args[0].tonum();
|
||||
double num = args[0].tonum();
|
||||
if (num<2) {
|
||||
return var::num(num);
|
||||
}
|
||||
double a=1,b=1,res=0;
|
||||
for(double i=1;i<num;i+=1) {
|
||||
res=a+b;
|
||||
a=b;
|
||||
b=res;
|
||||
double a = 1, b = 1, res = 0;
|
||||
for(double i = 1; i<num; ++i) {
|
||||
res = a+b;
|
||||
a = b;
|
||||
b = res;
|
||||
}
|
||||
return var::num(res);
|
||||
}
|
||||
|
@ -40,42 +40,43 @@ var quick_fib(var* args, usize size, gc* ngc) {
|
|||
u32 ghost_for_test;
|
||||
|
||||
void ghost_for_test_destructor(void* ptr) {
|
||||
std::cout<<"ghost_for_test::destructor (0x";
|
||||
std::cout<<std::hex<<(u64)ptr<<std::dec<<") {\n";
|
||||
std::cout << "ghost_for_test::destructor (0x";
|
||||
std::cout << std::hex << (u64)ptr << std::dec << ") {\n";
|
||||
delete (u32*)ptr;
|
||||
std::cout<<" delete 0x"<<std::hex<<(u64)ptr<<std::dec<<";\n";
|
||||
std::cout<<"}\n";
|
||||
std::cout << " delete 0x" << std::hex << (u64)ptr << std::dec << ";\n";
|
||||
std::cout << "}\n";
|
||||
}
|
||||
|
||||
var create_new_ghost(var* args, usize size, gc* ngc) {
|
||||
var res=ngc->alloc(vm_obj);
|
||||
var res = ngc->alloc(vm_obj);
|
||||
res.obj().set(ghost_for_test, new u32, &ngc->global_ghost_type_table);
|
||||
return res;
|
||||
}
|
||||
|
||||
var set_new_ghost(var* args, usize size, gc* ngc) {
|
||||
var res=args[0];
|
||||
var res = args[0];
|
||||
if (!res.objchk(ghost_for_test)) {
|
||||
std::cout<<"set_new_ghost: not ghost for test type.\n";
|
||||
std::cout << "set_new_ghost: not ghost for test type.\n";
|
||||
return nil;
|
||||
}
|
||||
f64 num=args[1].num();
|
||||
*((u32*)res.obj().ptr)=static_cast<u32>(num);
|
||||
std::cout<<"set_new_ghost: successfully set ghost = "<<num<<"\n";
|
||||
f64 num = args[1].num();
|
||||
*((u32*)res.obj().ptr) = static_cast<u32>(num);
|
||||
std::cout << "set_new_ghost: successfully set ghost = " << num << "\n";
|
||||
return nil;
|
||||
}
|
||||
|
||||
var print_new_ghost(var* args, usize size, gc* ngc) {
|
||||
var res=args[0];
|
||||
var res = args[0];
|
||||
if (!res.objchk(ghost_for_test)) {
|
||||
std::cout<<"print_new_ghost: not ghost for test type.\n";
|
||||
std::cout << "print_new_ghost: not ghost for test type.\n";
|
||||
return nil;
|
||||
}
|
||||
std::cout<<"print_new_ghost: "<<res.obj()<<" result = "<<*((u32*)res.obj().ptr)<<"\n";
|
||||
std::cout << "print_new_ghost: " << res.obj() << " result = "
|
||||
<< *((u32*)res.obj().ptr) << "\n";
|
||||
return nil;
|
||||
}
|
||||
|
||||
module_func_info func_tbl[]={
|
||||
module_func_info func_tbl[] = {
|
||||
{"fib", fib},
|
||||
{"quick_fib", quick_fib},
|
||||
{"create_ghost", create_new_ghost},
|
||||
|
@ -88,10 +89,10 @@ module_func_info func_tbl[]={
|
|||
|
||||
extern "C" module_func_info* get(ghost_register_table* table) {
|
||||
if (table->exists("fib_for_test")) {
|
||||
nasal_fib_module::ghost_for_test=table->get_ghost_type_index("fib_for_test");
|
||||
nasal_fib_module::ghost_for_test = table->get_ghost_type_index("fib_for_test");
|
||||
return nasal_fib_module::func_tbl;
|
||||
}
|
||||
nasal_fib_module::ghost_for_test=table->register_ghost_type(
|
||||
nasal_fib_module::ghost_for_test = table->register_ghost_type(
|
||||
"fib_for_test",
|
||||
nasal_fib_module::ghost_for_test_destructor
|
||||
);
|
||||
|
|
|
@ -145,7 +145,7 @@ void execute(
|
|||
// get running time
|
||||
if (cmd&VM_TIME) {
|
||||
f64 tm = (clk::now()-start).count()*1.0/den;
|
||||
std::clog << "process exited after " << tm << "s.\n\n";
|
||||
std::clog << " process exited after " << tm << "s.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ using u64 = std::uint64_t;
|
|||
using usize = std::size_t;
|
||||
using f64 = double;
|
||||
|
||||
const u32 STACK_DEPTH=4096;
|
||||
const u32 STACK_DEPTH = 4096;
|
||||
|
||||
f64 hex2f(const char*);
|
||||
f64 oct2f(const char*);
|
||||
|
|
|
@ -1210,12 +1210,6 @@ var builtin_millisec(var* local, gc& ngc) {
|
|||
return var::num(res);
|
||||
}
|
||||
|
||||
var builtin_sysargv(var* local, gc& ngc) {
|
||||
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];
|
||||
if (type.type!=vm_str) {
|
||||
|
@ -1356,7 +1350,6 @@ nasal_builtin_table builtin[] = {
|
|||
{"__costatus", builtin_costatus},
|
||||
{"__corun", builtin_corun},
|
||||
{"__millisec", builtin_millisec},
|
||||
{"__sysargv", builtin_sysargv},
|
||||
{"__gcextd", builtin_gcextend},
|
||||
{"__logtime", builtin_logtime},
|
||||
{"__ghosttype", builtin_ghosttype},
|
||||
|
|
|
@ -124,7 +124,6 @@ var builtin_coyield(var*, gc&);
|
|||
var builtin_costatus(var*, gc&);
|
||||
var builtin_corun(var*, gc&);
|
||||
var builtin_millisec(var*, gc&);
|
||||
var builtin_sysargv(var*, gc&);
|
||||
var builtin_gcextend(var*, gc&);
|
||||
var builtin_logtime(var*, gc&);
|
||||
var builtin_ghosttype(var*, gc&);
|
||||
|
|
|
@ -211,6 +211,21 @@ void codegen::func_gen(function* node) {
|
|||
// search symbols first, must use after loading parameters
|
||||
// or the location of symbols will change and cause fatal error
|
||||
find_symbol(block);
|
||||
// add special varibale "arg", which is used to store overflowed args
|
||||
// but if dynamic parameter is declared, this variable will be useless
|
||||
// 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)}
|
||||
auto arg = std::string("arg");
|
||||
// this is used to avoid confliction with defined parameter
|
||||
while(local_find(arg)>=0) {
|
||||
arg = "0" + arg;
|
||||
}
|
||||
add_symbol(arg);
|
||||
|
||||
in_iterloop.push(0);
|
||||
block_gen(block);
|
||||
in_iterloop.pop();
|
||||
|
@ -1094,13 +1109,7 @@ const error& codegen::compile(parse& parse, linker& import) {
|
|||
|
||||
// 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 special symbol arg here, which is used to store command line args
|
||||
add_symbol("arg");
|
||||
|
||||
find_symbol(parse.tree()); // search symbols first
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
std::vector<std::string> dbg::parse(const std::string& cmd) {
|
||||
std::vector<std::string> res;
|
||||
usize last=0;
|
||||
usize pos=cmd.find(" ", 0);
|
||||
usize last = 0, pos = cmd.find(" ", 0);
|
||||
while(pos!=std::string::npos) {
|
||||
if (pos>last) {
|
||||
res.push_back(cmd.substr(last, pos-last));
|
||||
}
|
||||
last=pos+1;
|
||||
pos=cmd.find(" ", last);
|
||||
last = pos+1;
|
||||
pos = cmd.find(" ", last);
|
||||
}
|
||||
if (last<cmd.length()) {
|
||||
res.push_back(cmd.substr(last));
|
||||
|
@ -18,7 +17,7 @@ std::vector<std::string> dbg::parse(const std::string& cmd) {
|
|||
}
|
||||
|
||||
u16 dbg::file_index(const std::string& filename) const {
|
||||
for(u16 i=0;i<fsize;++i) {
|
||||
for(u16 i = 0; i<fsize; ++i) {
|
||||
if (filename==files[i]) {
|
||||
return i;
|
||||
}
|
||||
|
@ -28,76 +27,78 @@ u16 dbg::file_index(const std::string& filename) const {
|
|||
|
||||
void dbg::err() {
|
||||
std::cerr
|
||||
<<"incorrect command\n"
|
||||
<<"input \'h\' to get help\n";
|
||||
<< "incorrect command\n"
|
||||
<< "input \'h\' to get help\n";
|
||||
}
|
||||
|
||||
void dbg::help() {
|
||||
std::clog
|
||||
<<"<option>\n"
|
||||
<<" h, help | get help\n"
|
||||
<<" bt, backtrace | get function call trace\n"
|
||||
<<" c, continue | run program until break point or exit\n"
|
||||
<<" f, file | see all the compiled files\n"
|
||||
<<" g, global | see global values\n"
|
||||
<<" l, local | see local values\n"
|
||||
<<" u, upval | see upvalue\n"
|
||||
<<" r, register | show vm register detail\n"
|
||||
<<" a, all | show global,local and upvalue\n"
|
||||
<<" n, next | execute next bytecode\n"
|
||||
<<" q, exit | exit debugger\n"
|
||||
<<"<option> <filename> <line>\n"
|
||||
<<" bk, break | set break point\n";
|
||||
<< "<option>\n"
|
||||
<< " h, help | get help\n"
|
||||
<< " bt, backtrace | get function call trace\n"
|
||||
<< " c, continue | run program until break point or exit\n"
|
||||
<< " f, file | see all the compiled files\n"
|
||||
<< " g, global | see global values\n"
|
||||
<< " l, local | see local values\n"
|
||||
<< " u, upval | see upvalue\n"
|
||||
<< " r, register | show vm register detail\n"
|
||||
<< " a, all | show global,local and upvalue\n"
|
||||
<< " n, next | execute next bytecode\n"
|
||||
<< " q, exit | exit debugger\n"
|
||||
<< "<option> <filename> <line>\n"
|
||||
<< " bk, break | set break point\n";
|
||||
}
|
||||
|
||||
void dbg::list_file() const {
|
||||
for(usize i=0; i<fsize; ++i) {
|
||||
std::clog<<"["<<i<<"] "<<files[i]<<"\n";
|
||||
for(usize i = 0; i<fsize; ++i) {
|
||||
std::clog << "[" << i << "] " << files[i] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void dbg::call_sort(const u64* arr) const {
|
||||
typedef std::pair<u32,u64> op;
|
||||
std::vector<op> opcall;
|
||||
u64 total=0;
|
||||
for(u32 i=0;i<op_ret+1;++i) {
|
||||
total+=arr[i];
|
||||
u64 total = 0;
|
||||
for(u32 i = 0; i<op_ret+1; ++i) {
|
||||
total += arr[i];
|
||||
opcall.push_back({i, arr[i]});
|
||||
}
|
||||
std::sort(opcall.begin(), opcall.end(),
|
||||
[](const op& a, const op& b) {return a.second>b.second;}
|
||||
);
|
||||
std::clog<<"\noperands call info (<1% ignored)\n";
|
||||
for(auto& i:opcall) {
|
||||
u64 rate=i.second*100/total;
|
||||
std::clog << "\noperands call info (<1% ignored)\n";
|
||||
for(auto& i : opcall) {
|
||||
u64 rate = i.second*100/total;
|
||||
if (!rate) {
|
||||
break;
|
||||
}
|
||||
std::clog<<" "<<opname[i.first]<<" : "<<i.second<<" ("<<rate<<"%)\n";
|
||||
std::clog << " " << opname[i.first] << " : ";
|
||||
std::clog << i.second << " (" << rate << "%)\n";
|
||||
}
|
||||
std::clog<<" total : "<<total<<'\n';
|
||||
std::clog << " total : " << total << '\n';
|
||||
}
|
||||
|
||||
void dbg::step_info() {
|
||||
u32 line=bytecode[ctx.pc].line==0?0:bytecode[ctx.pc].line-1;
|
||||
u32 begin=(line>>3)==0?0:((line>>3)<<3);
|
||||
u32 end=(1+(line>>3))<<3;
|
||||
u32 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1;
|
||||
u32 begin = (line>>3)==0? 0:((line>>3)<<3);
|
||||
u32 end = (1+(line>>3))<<3;
|
||||
src.load(files[bytecode[ctx.pc].fidx]);
|
||||
std::clog<<"\nsource code:\n";
|
||||
for(u32 i=begin;i<end && i<src.size();++i) {
|
||||
std::clog<<(i==line?back_white:reset)<<(i==line?"--> ":" ")<<src[i]<<reset<<"\n";
|
||||
std::clog << "\nsource code:\n";
|
||||
for(u32 i = begin; i<end && i<src.size(); ++i) {
|
||||
std::clog << (i==line? back_white:reset);
|
||||
std::clog << (i==line? "--> ":" ") << src[i] << reset << "\n";
|
||||
}
|
||||
|
||||
begin=(ctx.pc>>3)==0?0:((ctx.pc>>3)<<3);
|
||||
end=(1+(ctx.pc>>3))<<3;
|
||||
begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3);
|
||||
end = (1+(ctx.pc>>3))<<3;
|
||||
codestream::set(cnum, cstr, files);
|
||||
std::clog<<"next bytecode:\n";
|
||||
for(u32 i=begin;i<end && bytecode[i].op!=op_exit;++i) {
|
||||
std::clog << "next bytecode:\n";
|
||||
for(u32 i = begin; i<end && bytecode[i].op!=op_exit; ++i) {
|
||||
std::clog
|
||||
<<(i==ctx.pc?back_white:reset)
|
||||
<<(i==ctx.pc?"--> ":" ")
|
||||
<<codestream(bytecode[i], i)
|
||||
<<reset<<"\n";
|
||||
<< (i==ctx.pc? back_white:reset)
|
||||
<< (i==ctx.pc? "--> ":" ")
|
||||
<< codestream(bytecode[i], i)
|
||||
<< reset << "\n";
|
||||
}
|
||||
stackinfo(10);
|
||||
}
|
||||
|
@ -114,11 +115,11 @@ void dbg::interact() {
|
|||
return;
|
||||
}
|
||||
|
||||
next=false;
|
||||
next = false;
|
||||
std::string cmd;
|
||||
step_info();
|
||||
while(true) {
|
||||
std::clog<<">> ";
|
||||
std::clog << ">> ";
|
||||
std::getline(std::cin, cmd);
|
||||
auto res=parse(cmd);
|
||||
if (res.size()==0) {
|
||||
|
@ -134,22 +135,22 @@ void dbg::interact() {
|
|||
case dbg_cmd::cmd_upval: ustate(); break;
|
||||
case dbg_cmd::cmd_register: reginfo(); break;
|
||||
case dbg_cmd::cmd_show_all: detail(); break;
|
||||
case dbg_cmd::cmd_next: next=true; return;
|
||||
case dbg_cmd::cmd_next: next = true; return;
|
||||
case dbg_cmd::cmd_exit: std::exit(0);
|
||||
default: err(); break;
|
||||
}
|
||||
} else if (res.size()==3 &&
|
||||
get_cmd_type(res[0])==dbg_cmd::cmd_break_point) {
|
||||
bk_fidx=file_index(res[1]);
|
||||
bk_fidx = file_index(res[1]);
|
||||
if (bk_fidx==65535) {
|
||||
std::clog<<"cannot find file named `"<<res[1]<<"`\n";
|
||||
std::clog << "cannot find file named `" << res[1] << "`\n";
|
||||
continue;
|
||||
}
|
||||
i32 tmp=atoi(res[2].c_str());
|
||||
i32 tmp = atoi(res[2].c_str());
|
||||
if (tmp<=0) {
|
||||
std::clog<<"incorrect line number `"<<res[2]<<"`\n";
|
||||
std::clog << "incorrect line number `" << res[2] << "`\n";
|
||||
} else {
|
||||
bk_line=tmp;
|
||||
bk_line = tmp;
|
||||
}
|
||||
} else {
|
||||
err();
|
||||
|
@ -161,17 +162,17 @@ void dbg::run(
|
|||
const codegen& gen,
|
||||
const linker& linker,
|
||||
const std::vector<std::string>& argv) {
|
||||
verbose=true;
|
||||
fsize=linker.filelist().size();
|
||||
verbose = true;
|
||||
fsize = linker.filelist().size();
|
||||
init(gen.strs(),
|
||||
gen.nums(),
|
||||
gen.codes(),
|
||||
gen.globals(),
|
||||
linker.filelist(),
|
||||
argv);
|
||||
u64 count[op_ret+1]={0};
|
||||
u64 count[op_ret+1] = {0};
|
||||
typedef void (dbg::*nafunc)();
|
||||
const nafunc oprs[]={
|
||||
const nafunc oprs[] = {
|
||||
nullptr, &dbg::o_intg,
|
||||
&dbg::o_intl, &dbg::o_loadg,
|
||||
&dbg::o_loadl, &dbg::o_loadu,
|
||||
|
@ -218,7 +219,7 @@ void dbg::run(
|
|||
&dbg::o_ret
|
||||
};
|
||||
std::vector<u32> code;
|
||||
for(auto& i:gen.codes()) {
|
||||
for(auto& i : gen.codes()) {
|
||||
code.push_back(i.op);
|
||||
imm.push_back(i.num);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ std::ostream& back_white(std::ostream& s) {
|
|||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0xf0);
|
||||
#else
|
||||
s<<"\033[7m";
|
||||
s << "\033[7m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ std::ostream& red(std::ostream& s) {
|
|||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0c);
|
||||
#else
|
||||
s<<"\033[91;1m";
|
||||
s << "\033[91;1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ std::ostream& cyan(std::ostream& s) {
|
|||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x03);
|
||||
#else
|
||||
s<<"\033[36;1m";
|
||||
s << "\033[36;1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ std::ostream& orange(std::ostream& s) {
|
|||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0e);
|
||||
#else
|
||||
s<<"\033[93;1m";
|
||||
s << "\033[93;1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ std::ostream& white(std::ostream& s) {
|
|||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0f);
|
||||
#else
|
||||
s<<"\033[0m\033[1m";
|
||||
s << "\033[0m\033[1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ std::ostream& reset(std::ostream& s) {
|
|||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), reset_ter_color.scr.wAttributes);
|
||||
#else
|
||||
s<<"\033[0m";
|
||||
s << "\033[0m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ void flstream::load(const std::string& f) {
|
|||
res.clear();
|
||||
std::ifstream in(f, std::ios::binary);
|
||||
if (in.fail()) {
|
||||
std::cerr<<red<<"src: "<<reset<<"cannot open <"<<f<<">\n";
|
||||
std::cerr << red << "src: " << reset << "cannot open <" << f << ">\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
|
@ -85,22 +85,22 @@ void flstream::load(const std::string& f) {
|
|||
}
|
||||
|
||||
void error::fatal(const std::string& stage, const std::string& info) {
|
||||
std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
|
||||
std::cerr << red << stage << ": " << white << info << reset << "\n";
|
||||
if (file.length()) {
|
||||
std::cerr<<cyan<<" --> "<<red<<file<<reset<<"\n\n";
|
||||
std::cerr << cyan << " --> " << red << file << reset << "\n\n";
|
||||
} else {
|
||||
std::cerr<<reset<<"\n";
|
||||
std::cerr << reset << "\n";
|
||||
}
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
void error::err(const std::string& stage, const std::string& info) {
|
||||
++cnt;
|
||||
std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
|
||||
std::cerr << red << stage << ": " << white << info << reset << "\n";
|
||||
if (file.length()) {
|
||||
std::cerr<<cyan<<" --> "<<red<<file<<reset<<"\n\n";
|
||||
std::cerr << cyan << " --> " << red << file << reset << "\n\n";
|
||||
} else {
|
||||
std::cerr<<reset<<"\n";
|
||||
std::cerr << reset << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,8 +112,9 @@ void error::err(
|
|||
++cnt;
|
||||
|
||||
std::cerr
|
||||
<<red<<stage<<": "<<white<<info<<reset<<"\n"<<cyan<<" --> "
|
||||
<<red<<loc.file<<":"<<loc.begin_line<<":"<<loc.begin_column+1<<reset<<"\n";
|
||||
<< red << stage << ": " << white << info << reset << "\n" << cyan << " --> "
|
||||
<< red << loc.file << ":" << loc.begin_line << ":" << loc.begin_column+1
|
||||
<< reset << "\n";
|
||||
|
||||
const usize maxlen = std::to_string(loc.end_line).length();
|
||||
const std::string iden = identation(maxlen);
|
||||
|
@ -125,7 +126,8 @@ void error::err(
|
|||
|
||||
if (loc.begin_line<line && line<loc.end_line) {
|
||||
if (line==loc.begin_line+1) {
|
||||
std::cerr<<cyan<<iden<<" | "<<reset<<"...\n"<<cyan<<iden<<" | "<<reset<<"\n";
|
||||
std::cerr << cyan << iden << " | " << reset << "...\n"
|
||||
<< cyan << iden << " | " << reset << "\n";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -136,37 +138,37 @@ void error::err(
|
|||
}
|
||||
|
||||
const std::string& code=res[line-1];
|
||||
std::cerr<<cyan<<leftpad(line, maxlen)<<" | "<<reset<<code<<"\n";
|
||||
std::cerr << cyan << leftpad(line, maxlen) << " | " << reset << code << "\n";
|
||||
// output underline
|
||||
std::cerr<<cyan<<iden<<" | "<<reset;
|
||||
std::cerr << cyan << iden << " | " << reset;
|
||||
if (loc.begin_line==loc.end_line) {
|
||||
for(u32 i=0; i<loc.begin_column; ++i) {
|
||||
std::cerr<<char(" \t"[code[i]=='\t']);
|
||||
for(u32 i = 0; i<loc.begin_column; ++i) {
|
||||
std::cerr << char(" \t"[code[i]=='\t']);
|
||||
}
|
||||
for(u32 i=loc.begin_column ;i<loc.end_column; ++i) {
|
||||
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^")<<reset;
|
||||
for(u32 i = loc.begin_column ;i<loc.end_column; ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^") << reset;
|
||||
}
|
||||
} else if (line==loc.begin_line) {
|
||||
for(u32 i=0; i<loc.begin_column; ++i) {
|
||||
std::cerr<<char(" \t"[code[i]=='\t']);
|
||||
for(u32 i = 0; i<loc.begin_column; ++i) {
|
||||
std::cerr << char(" \t"[code[i]=='\t']);
|
||||
}
|
||||
for(u32 i=loc.begin_column; i<code.size(); ++i) {
|
||||
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^")<<reset;
|
||||
for(u32 i = loc.begin_column; i<code.size(); ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^") << reset;
|
||||
}
|
||||
} else if (loc.begin_line<line && line<loc.end_line) {
|
||||
for(u32 i=0; i<code.size(); ++i) {
|
||||
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^");
|
||||
for(u32 i = 0; i<code.size(); ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^");
|
||||
}
|
||||
} else {
|
||||
for(u32 i=0; i<loc.end_column; ++i) {
|
||||
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^");
|
||||
for(u32 i = 0; i<loc.end_column; ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^");
|
||||
}
|
||||
}
|
||||
if (line==loc.end_line) {
|
||||
std::cerr<<reset;
|
||||
std::cerr << reset;
|
||||
} else {
|
||||
std::cerr<<reset<<"\n";
|
||||
std::cerr << reset << "\n";
|
||||
}
|
||||
}
|
||||
std::cerr<<"\n\n";
|
||||
std::cerr << "\n\n";
|
||||
}
|
119
src/nasal_gc.cpp
119
src/nasal_gc.cpp
|
@ -337,6 +337,23 @@ nas_map& var::map() {
|
|||
return *val.gcobj->ptr.map;
|
||||
}
|
||||
|
||||
void gc::do_mark_sweep() {
|
||||
using clk = std::chrono::high_resolution_clock;
|
||||
auto begin = clk::now();
|
||||
mark();
|
||||
auto mark_end = clk::now();
|
||||
sweep();
|
||||
auto sweep_end = clk::now();
|
||||
|
||||
auto total_time = (sweep_end-begin).count();
|
||||
auto mark_time = (mark_end-begin).count();
|
||||
auto sweep_time = (sweep_end-mark_end).count();
|
||||
worktime += total_time;
|
||||
max_time = max_time<total_time? total_time:max_time;
|
||||
max_mark_time = max_mark_time<mark_time? mark_time:max_mark_time;
|
||||
max_sweep_time = max_sweep_time<sweep_time? sweep_time:max_sweep_time;
|
||||
}
|
||||
|
||||
void gc::mark() {
|
||||
std::vector<var> bfs;
|
||||
mark_context(bfs);
|
||||
|
@ -389,13 +406,17 @@ void gc::mark_var(std::vector<var>& bfs_queue, var& value) {
|
|||
|
||||
void gc::mark_vec(std::vector<var>& bfs_queue, nas_vec& vec) {
|
||||
for(auto& i : vec.elems) {
|
||||
bfs_queue.push_back(i);
|
||||
if (i.type>vm_num) {
|
||||
bfs_queue.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gc::mark_hash(std::vector<var>& bfs_queue, nas_hash& hash) {
|
||||
for(auto& i : hash.elems) {
|
||||
bfs_queue.push_back(i.second);
|
||||
if (i.second.type>vm_num) {
|
||||
bfs_queue.push_back(i.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,24 +523,39 @@ void gc::clear() {
|
|||
env_argv.clear();
|
||||
}
|
||||
|
||||
void gc::info() {
|
||||
void gc::info() const {
|
||||
|
||||
using std::left;
|
||||
using std::setw;
|
||||
using std::setfill;
|
||||
|
||||
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
|
||||
};
|
||||
const char* name[] = {
|
||||
"string ",
|
||||
"vector ",
|
||||
"hashmap ",
|
||||
"function ",
|
||||
"upvalue ",
|
||||
"object ",
|
||||
"string",
|
||||
"vector",
|
||||
"hashmap",
|
||||
"function",
|
||||
"upvalue",
|
||||
"object",
|
||||
"coroutine",
|
||||
"mapper "
|
||||
"mapper",
|
||||
nullptr
|
||||
};
|
||||
|
||||
usize indent = 0;
|
||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||
usize len = 0;
|
||||
usize indent = 0, len = 0;
|
||||
for(usize i = 0; used_table_name[i]; ++i) {
|
||||
len = std::string(used_table_name[i]).length();
|
||||
indent = indent<len? len:indent;
|
||||
}
|
||||
for(usize i = 0; name[i]; ++i) {
|
||||
len = std::string(name[i]).length();
|
||||
indent = indent<len? len:indent;
|
||||
}
|
||||
for(u32 i = 0; i<gc_type_size; ++i) {
|
||||
len = std::to_string(gcnt[i]).length();
|
||||
indent = indent<len? len:indent;
|
||||
len = std::to_string(acnt[i]).length();
|
||||
|
@ -527,51 +563,60 @@ void gc::info() {
|
|||
len = std::to_string(size[i]).length();
|
||||
indent = indent<len? len:indent;
|
||||
}
|
||||
auto indent_string = std::string("--");
|
||||
for(usize i = 0; i<indent; ++i) {
|
||||
indent_string += "-";
|
||||
}
|
||||
indent_string = 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";
|
||||
|
||||
double total = 0;
|
||||
std::clog << "\ngc info (gc count|alloc count|memory size)\n";
|
||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||
if (!gcnt[i] && !acnt[i] && !size[i]) {
|
||||
continue;
|
||||
}
|
||||
total += gcnt[i];
|
||||
std::clog << " " << name[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 << indent_string << "\n";
|
||||
|
||||
auto den = std::chrono::high_resolution_clock::duration::period::den;
|
||||
std::clog << " gc time | " << worktime*1.0/den*1000 << " ms\n";
|
||||
if (total) {
|
||||
std::clog << " avg time | " << worktime*1.0/den*1000/total << " ms\n";
|
||||
std::clog << " max gc | " << max_time*1.0/den*1000 << " ms\n";
|
||||
std::clog << " max mark | " << max_mark_time*1.0/den*1000 << " ms\n";
|
||||
std::clog << " max sweep | " << max_sweep_time*1.0/den*1000 << " ms\n";
|
||||
}
|
||||
std::clog<<"\n";
|
||||
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";
|
||||
|
||||
std::clog << " " << left << setw(indent) << setfill(' ') << "gc time";
|
||||
std::clog << " | " << worktime*1.0/den*1000 << " ms\n";
|
||||
std::clog << " " << left << setw(indent) << setfill(' ') << "avg time";
|
||||
std::clog << " | " << worktime*1.0/den*1000/total << " ms\n";
|
||||
std::clog << " " << left << setw(indent) << setfill(' ') << "max gc";
|
||||
std::clog << " | " << max_time*1.0/den*1000 << " ms\n";
|
||||
std::clog << " " << left << setw(indent) << setfill(' ') << "max mark";
|
||||
std::clog << " | " << max_mark_time*1.0/den*1000 << " ms\n";
|
||||
std::clog << " " << left << setw(indent) << setfill(' ') << "max sweep";
|
||||
std::clog << " | " << max_sweep_time*1.0/den*1000 << " ms\n";
|
||||
std::clog << indent_string << "\n";
|
||||
}
|
||||
|
||||
var gc::alloc(u8 type) {
|
||||
using clk = std::chrono::high_resolution_clock;
|
||||
const u8 index = type-vm_str;
|
||||
++acnt[index];
|
||||
if (unused[index].empty()) {
|
||||
++gcnt[index];
|
||||
auto begin = clk::now();
|
||||
mark();
|
||||
auto mark_end = clk::now();
|
||||
sweep();
|
||||
auto sweep_end = clk::now();
|
||||
|
||||
auto total_time = (sweep_end-begin).count();
|
||||
auto mark_time = (mark_end-begin).count();
|
||||
auto sweep_time = (sweep_end-mark_end).count();
|
||||
worktime += total_time;
|
||||
max_time = max_time<total_time? total_time:max_time;
|
||||
max_mark_time = max_mark_time<mark_time? mark_time:max_mark_time;
|
||||
max_sweep_time = max_sweep_time<sweep_time? sweep_time:max_sweep_time;
|
||||
do_mark_sweep();
|
||||
}
|
||||
if (unused[index].empty()) {
|
||||
extend(type);
|
||||
|
|
|
@ -383,6 +383,7 @@ struct gc {
|
|||
|
||||
private:
|
||||
/* gc functions */
|
||||
void do_mark_sweep();
|
||||
void mark();
|
||||
void mark_context(std::vector<var>&);
|
||||
void mark_var(std::vector<var>&, var&);
|
||||
|
@ -398,7 +399,7 @@ public:
|
|||
void extend(u8);
|
||||
void init(const std::vector<std::string>&, const std::vector<std::string>&);
|
||||
void clear();
|
||||
void info();
|
||||
void info() const;
|
||||
var alloc(const u8);
|
||||
void ctxchg(nas_co&);
|
||||
void ctxreserve();
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#include "nasal_import.h"
|
||||
|
||||
linker::linker(error& e): show_path(false), lib_loaded(false), err(e) {
|
||||
char sep=is_windows()? ';':':';
|
||||
std::string PATH=getenv("PATH");
|
||||
usize last=0;
|
||||
usize pos=PATH.find(sep, 0);
|
||||
linker::linker(error& e):
|
||||
show_path(false), lib_loaded(false), err(e) {
|
||||
char sep = is_windows()? ';':':';
|
||||
std::string PATH = getenv("PATH");
|
||||
usize last = 0, pos = PATH.find(sep, 0);
|
||||
while(pos!=std::string::npos) {
|
||||
std::string dirpath=PATH.substr(last, pos-last);
|
||||
std::string dirpath = PATH.substr(last, pos-last);
|
||||
if (dirpath.length()) {
|
||||
envpath.push_back(dirpath);
|
||||
}
|
||||
last=pos+1;
|
||||
pos=PATH.find(sep, last);
|
||||
last = pos+1;
|
||||
pos = PATH.find(sep, last);
|
||||
}
|
||||
if (last!=PATH.length()) {
|
||||
envpath.push_back(PATH.substr(last));
|
||||
|
@ -132,7 +132,7 @@ bool linker::exist(const std::string& file) {
|
|||
|
||||
void linker::link(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()) {
|
||||
for(auto& i : old_tree_root->get_expressions()) {
|
||||
new_tree_root->add_expression(i);
|
||||
}
|
||||
// clean old root
|
||||
|
|
|
@ -7,43 +7,43 @@
|
|||
#include "nasal_lexer.h"
|
||||
|
||||
bool lexer::skip(char c) {
|
||||
return c==' '||c=='\n'||c=='\t'||c=='\r'||c==0;
|
||||
return c==' ' || c=='\n' || c=='\t' || c=='\r' || c==0;
|
||||
}
|
||||
|
||||
bool lexer::is_id(char c) {
|
||||
return (c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||(c<0);
|
||||
return (c=='_') || ('a'<=c && c<='z') || ('A'<=c && c<='Z') || (c<0);
|
||||
}
|
||||
|
||||
bool lexer::is_hex(char c) {
|
||||
return ('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F');
|
||||
return ('0'<=c && c<='9') || ('a'<=c && c<='f') || ('A'<=c && c<='F');
|
||||
}
|
||||
|
||||
bool lexer::is_oct(char c) {
|
||||
return '0'<=c&&c<='7';
|
||||
return '0'<=c && c<='7';
|
||||
}
|
||||
|
||||
bool lexer::is_dec(char c) {
|
||||
return '0'<=c&&c<='9';
|
||||
return '0'<=c && c<='9';
|
||||
}
|
||||
|
||||
bool lexer::is_str(char c) {
|
||||
return c=='\''||c=='\"'||c=='`';
|
||||
return c=='\'' || c=='\"' || 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=='}' || c==',' || c==';' ||
|
||||
c==':' || c=='?' || c=='`' || c=='@' ||
|
||||
c=='%' || c=='$' || c=='\\'
|
||||
);
|
||||
}
|
||||
|
||||
bool lexer::is_calc_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=='~' || c=='|' || c=='&' || c=='^'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,10 @@ void lexer::skip_note() {
|
|||
|
||||
void lexer::err_char() {
|
||||
++column;
|
||||
char c=res[ptr++];
|
||||
err.err("lexer", {line, column-1, line, column, filename}, "invalid character 0x"+chrhex(c));
|
||||
char c = res[ptr++];
|
||||
err.err("lexer",
|
||||
{line, column-1, line, column, filename},
|
||||
"invalid character 0x"+chrhex(c));
|
||||
err.fatal("lexer", "fatal error occurred, stop");
|
||||
}
|
||||
|
||||
|
@ -81,220 +83,241 @@ void lexer::open(const std::string& file) {
|
|||
}
|
||||
|
||||
tok lexer::get_type(const std::string& str) {
|
||||
return typetbl.count(str)?typetbl.at(str):tok::null;
|
||||
return typetbl.count(str)? typetbl.at(str):tok::null;
|
||||
}
|
||||
|
||||
std::string lexer::utf8_gen() {
|
||||
std::string str="";
|
||||
std::string str = "";
|
||||
while(ptr<res.size() && res[ptr]<0) {
|
||||
std::string tmp="";
|
||||
u32 nbytes=utf8_hdchk(res[ptr]);
|
||||
std::string tmp = "";
|
||||
u32 nbytes = utf8_hdchk(res[ptr]);
|
||||
if (!nbytes) {
|
||||
++ptr;
|
||||
++column;
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp+=res[ptr++];
|
||||
for(u32 i=0;i<nbytes;++i,++ptr) {
|
||||
tmp += res[ptr++];
|
||||
for(u32 i = 0; i<nbytes; ++i, ++ptr) {
|
||||
if (ptr<res.size() && (res[ptr]&0xc0)==0x80) {
|
||||
tmp+=res[ptr];
|
||||
tmp += res[ptr];
|
||||
}
|
||||
}
|
||||
|
||||
// utf8 character's total length is 1+nbytes
|
||||
if (tmp.length()!=1+nbytes) {
|
||||
++column;
|
||||
std::string utf_info="0x"+chrhex(tmp[0]);
|
||||
for(u32 i=1;i<tmp.size();++i) {
|
||||
utf_info+=" 0x"+chrhex(tmp[i]);
|
||||
std::string utf_info = "0x"+chrhex(tmp[0]);
|
||||
for(u32 i = 1; i<tmp.size(); ++i) {
|
||||
utf_info += " 0x"+chrhex(tmp[i]);
|
||||
}
|
||||
err.err("lexer", {line, column-1, line, column, filename}, "invalid utf-8 <"+utf_info+">");
|
||||
err.err("lexer",
|
||||
{line, column-1, line, column, filename},
|
||||
"invalid utf-8 <"+utf_info+">");
|
||||
err.fatal("lexer", "fatal error occurred, stop");
|
||||
}
|
||||
str+=tmp;
|
||||
column+=2; // may have some problems because not all the unicode takes 2 space
|
||||
str += tmp;
|
||||
column += 2; // may have some problems because not all the unicode takes 2 space
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
token lexer::id_gen() {
|
||||
u32 begin_line=line;
|
||||
u32 begin_column=column;
|
||||
std::string str="";
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
std::string str = "";
|
||||
while(ptr<res.size() && (is_id(res[ptr])||is_dec(res[ptr]))) {
|
||||
if (res[ptr]<0) { // utf-8
|
||||
str+=utf8_gen();
|
||||
str += utf8_gen();
|
||||
} else { // ascii
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
++column;
|
||||
}
|
||||
}
|
||||
tok type=get_type(str);
|
||||
return {{begin_line, begin_column, line, column, filename}, (type!=tok::null)?type:tok::id, str};
|
||||
tok type = get_type(str);
|
||||
return {
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
(type!=tok::null)? type:tok::id, str};
|
||||
}
|
||||
|
||||
token lexer::num_gen() {
|
||||
u32 begin_line=line;
|
||||
u32 begin_column=column;
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
// generate hex number
|
||||
if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x') {
|
||||
std::string str="0x";
|
||||
ptr+=2;
|
||||
std::string str = "0x";
|
||||
ptr += 2;
|
||||
while(ptr<res.size() && is_hex(res[ptr])) {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
}
|
||||
column+=str.length();
|
||||
if (str.length()<3) { // "0x"
|
||||
err.err("lexer", {begin_line, begin_column, line, column, filename}, "invalid number `"+str+"`");
|
||||
column += str.length();
|
||||
// "0x"
|
||||
if (str.length()<3) {
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
}
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||
} else if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o') { // generate oct number
|
||||
std::string str="0o";
|
||||
ptr+=2;
|
||||
std::string str = "0o";
|
||||
ptr += 2;
|
||||
while(ptr<res.size() && is_oct(res[ptr])) {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
}
|
||||
bool erfmt=false;
|
||||
bool erfmt = false;
|
||||
while(ptr<res.size() && (is_dec(res[ptr]) || is_hex(res[ptr]))) {
|
||||
erfmt=true;
|
||||
str+=res[ptr++];
|
||||
erfmt = true;
|
||||
str += res[ptr++];
|
||||
}
|
||||
column+=str.length();
|
||||
column += str.length();
|
||||
if (str.length()==2 || erfmt) {
|
||||
err.err("lexer", {begin_line, begin_column, line, column, filename}, "invalid number `"+str+"`");
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
}
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||
}
|
||||
// generate dec number
|
||||
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||
std::string str="";
|
||||
std::string str = "";
|
||||
while(ptr<res.size() && is_dec(res[ptr])) {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
}
|
||||
if (ptr<res.size() && res[ptr]=='.') {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
while(ptr<res.size() && is_dec(res[ptr])) {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
}
|
||||
// "xxxx." is not a correct number
|
||||
if (str.back()=='.') {
|
||||
column+=str.length();
|
||||
err.err("lexer",{begin_line, begin_column, line, column, filename}, "invalid number `"+str+"`");
|
||||
column += str.length();
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
||||
}
|
||||
}
|
||||
if (ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E')) {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
if (ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+')) {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
}
|
||||
while(ptr<res.size() && is_dec(res[ptr])) {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
}
|
||||
// "xxxe(-|+)" is not a correct number
|
||||
if (str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+') {
|
||||
column+=str.length();
|
||||
err.err("lexer",{begin_line, begin_column, line, column, filename}, "invalid number `"+str+"`");
|
||||
column += str.length();
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
||||
}
|
||||
}
|
||||
column+=str.length();
|
||||
column += str.length();
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||
}
|
||||
|
||||
token lexer::str_gen() {
|
||||
u32 begin_line=line;
|
||||
u32 begin_column=column;
|
||||
std::string str="";
|
||||
const char begin=res[ptr];
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
std::string str = "";
|
||||
const char begin = res[ptr];
|
||||
++column;
|
||||
while(++ptr<res.size() && res[ptr]!=begin) {
|
||||
++column;
|
||||
if (res[ptr]=='\n') {
|
||||
column=0;
|
||||
column = 0;
|
||||
++line;
|
||||
}
|
||||
if (res[ptr]=='\\' && ptr+1<res.size()) {
|
||||
++column;
|
||||
++ptr;
|
||||
switch(res[ptr]) {
|
||||
case '0': str+='\0'; break;
|
||||
case 'a': str+='\a'; break;
|
||||
case 'b': str+='\b'; break;
|
||||
case 'e': str+='\033'; break;
|
||||
case 't': str+='\t'; break;
|
||||
case 'n': str+='\n'; break;
|
||||
case 'v': str+='\v'; break;
|
||||
case 'f': str+='\f'; break;
|
||||
case 'r': str+='\r'; break;
|
||||
case '?': str+='\?'; break;
|
||||
case '\\':str+='\\'; break;
|
||||
case '\'':str+='\''; break;
|
||||
case '\"':str+='\"'; break;
|
||||
default: str+=res[ptr];break;
|
||||
case '0': str += '\0'; break;
|
||||
case 'a': str += '\a'; break;
|
||||
case 'b': str += '\b'; break;
|
||||
case 'e': str += '\033'; break;
|
||||
case 't': str += '\t'; break;
|
||||
case 'n': str += '\n'; break;
|
||||
case 'v': str += '\v'; break;
|
||||
case 'f': str += '\f'; break;
|
||||
case 'r': str += '\r'; break;
|
||||
case '?': str += '\?'; break;
|
||||
case '\\':str += '\\'; break;
|
||||
case '\'':str += '\''; break;
|
||||
case '\"':str += '\"'; break;
|
||||
default: str += res[ptr];break;
|
||||
}
|
||||
if (res[ptr]=='\n') {
|
||||
column=0;
|
||||
column = 0;
|
||||
++line;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
str+=res[ptr];
|
||||
str += res[ptr];
|
||||
}
|
||||
// check if this string ends with a " or '
|
||||
if (ptr++>=res.size()) {
|
||||
err.err("lexer", {begin_line, begin_column, line, column, filename}, "get EOF when generating string");
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"get EOF when generating string");
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
||||
}
|
||||
++column;
|
||||
if (begin=='`' && str.length()!=1) {
|
||||
err.err("lexer", {begin_line, begin_column, line, column, filename}, "\'`\' is used for string including one character");
|
||||
|
||||
// if is not utf8, 1+utf8_hdchk should be 1
|
||||
if (begin=='`' && str.length()!=1+utf8_hdchk(str[0])) {
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"\'`\' is used for string including one character");
|
||||
}
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
||||
}
|
||||
|
||||
token lexer::single_opr() {
|
||||
u32 begin_line=line;
|
||||
u32 begin_column=column;
|
||||
std::string str(1,res[ptr]);
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
std::string str(1, res[ptr]);
|
||||
++column;
|
||||
tok type=get_type(str);
|
||||
tok type = get_type(str);
|
||||
if (type==tok::null) {
|
||||
err.err("lexer", {begin_line, begin_column, line, column, filename}, "invalid operator `"+str+"`");
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid operator `"+str+"`");
|
||||
}
|
||||
++ptr;
|
||||
return {{begin_line, begin_column, line, column, filename}, type, str};
|
||||
}
|
||||
|
||||
token lexer::dots() {
|
||||
u32 begin_line=line;
|
||||
u32 begin_column=column;
|
||||
std::string str=".";
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
std::string str = ".";
|
||||
if (ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.') {
|
||||
str+="..";
|
||||
str += "..";
|
||||
}
|
||||
ptr+=str.length();
|
||||
column+=str.length();
|
||||
ptr += str.length();
|
||||
column += str.length();
|
||||
return {{begin_line, begin_column, line, column, filename}, get_type(str), str};
|
||||
}
|
||||
|
||||
token lexer::calc_opr() {
|
||||
u32 begin_line=line;
|
||||
u32 begin_column=column;
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
// get calculation operator
|
||||
std::string str(1,res[ptr++]);
|
||||
std::string str(1, res[ptr++]);
|
||||
if (ptr<res.size() && res[ptr]=='=') {
|
||||
str+=res[ptr++];
|
||||
str += res[ptr++];
|
||||
}
|
||||
column+=str.length();
|
||||
column += str.length();
|
||||
return {{begin_line, begin_column, line, column, filename}, get_type(str), str};
|
||||
}
|
||||
|
||||
const error& lexer::scan(const std::string& file) {
|
||||
line=1;
|
||||
column=0;
|
||||
ptr=0;
|
||||
line = 1;
|
||||
column = 0;
|
||||
ptr = 0;
|
||||
open(file);
|
||||
|
||||
while(ptr<res.size()) {
|
||||
|
@ -303,7 +326,7 @@ const error& lexer::scan(const std::string& file) {
|
|||
++column;
|
||||
if (res[ptr++]=='\n') {
|
||||
++line;
|
||||
column=0;
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
if (ptr>=res.size()) {
|
||||
|
@ -328,6 +351,6 @@ const error& lexer::scan(const std::string& file) {
|
|||
}
|
||||
}
|
||||
toks.push_back({{line, column, line, column, filename}, tok::eof, "<eof>"});
|
||||
res="";
|
||||
res = "";
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -85,14 +85,14 @@ bool is_superh() {
|
|||
}
|
||||
|
||||
f64 hex2f(const char* str) {
|
||||
f64 ret=0;
|
||||
f64 ret = 0;
|
||||
for(; *str; ++str) {
|
||||
if ('0'<=*str && *str<='9') {
|
||||
ret=ret*16+(*str-'0');
|
||||
ret = ret*16+(*str-'0');
|
||||
} else if ('a'<=*str && *str<='f') {
|
||||
ret=ret*16+(*str-'a'+10);
|
||||
ret = ret*16+(*str-'a'+10);
|
||||
} else if ('A'<=*str && *str<='F') {
|
||||
ret=ret*16+(*str-'A'+10);
|
||||
ret = ret*16+(*str-'A'+10);
|
||||
} else {
|
||||
return nan("");
|
||||
}
|
||||
|
@ -101,9 +101,9 @@ f64 hex2f(const char* str) {
|
|||
}
|
||||
|
||||
f64 oct2f(const char* str) {
|
||||
f64 ret=0;
|
||||
f64 ret = 0;
|
||||
while('0'<=*str && *str<'8') {
|
||||
ret=ret*8+(*str++-'0');
|
||||
ret = ret*8+(*str++-'0');
|
||||
}
|
||||
if (*str) {
|
||||
return nan("");
|
||||
|
@ -118,9 +118,9 @@ f64 oct2f(const char* str) {
|
|||
// but this also makes 0.1+0.2==0.3,
|
||||
// not another result that you may get in other languages.
|
||||
f64 dec2f(const char* str) {
|
||||
f64 ret=0,negative=1,num_pow=0;
|
||||
f64 ret = 0, negative = 1, num_pow = 0;
|
||||
while('0'<=*str && *str<='9') {
|
||||
ret=ret*10+(*str++-'0');
|
||||
ret = ret*10+(*str++-'0');
|
||||
}
|
||||
if (!*str) {
|
||||
return ret;
|
||||
|
@ -129,10 +129,10 @@ f64 dec2f(const char* str) {
|
|||
if (!*++str) {
|
||||
return nan("");
|
||||
}
|
||||
num_pow=0.1;
|
||||
num_pow = 0.1;
|
||||
while('0'<=*str && *str<='9') {
|
||||
ret+=num_pow*(*str++-'0');
|
||||
num_pow*=0.1;
|
||||
ret += num_pow*(*str++-'0');
|
||||
num_pow *= 0.1;
|
||||
}
|
||||
if (!*str) {
|
||||
return ret;
|
||||
|
@ -145,14 +145,14 @@ f64 dec2f(const char* str) {
|
|||
return nan("");
|
||||
}
|
||||
if (*str=='-' || *str=='+') {
|
||||
negative=(*str++=='-'? -1:1);
|
||||
negative = (*str++=='-'? -1:1);
|
||||
}
|
||||
if (!*str) {
|
||||
return nan("");
|
||||
}
|
||||
num_pow=0;
|
||||
num_pow = 0;
|
||||
while('0'<=*str && *str<='9') {
|
||||
num_pow=num_pow*10+(*str++-'0');
|
||||
num_pow = num_pow*10+(*str++-'0');
|
||||
}
|
||||
if (*str) {
|
||||
return nan("");
|
||||
|
@ -161,27 +161,27 @@ f64 dec2f(const char* str) {
|
|||
}
|
||||
|
||||
f64 str2num(const char* str) {
|
||||
bool negative=false;
|
||||
f64 res=0;
|
||||
bool negative = false;
|
||||
f64 res = 0;
|
||||
if (*str=='-' || *str=='+') {
|
||||
negative=(*str++=='-');
|
||||
negative = (*str++=='-');
|
||||
}
|
||||
if (!*str) {
|
||||
return nan("");
|
||||
}
|
||||
if (str[0]=='0' && str[1]=='x') {
|
||||
res=hex2f(str+2);
|
||||
res = hex2f(str+2);
|
||||
} else if (str[0]=='0' && str[1]=='o') {
|
||||
res=oct2f(str+2);
|
||||
res = oct2f(str+2);
|
||||
} else {
|
||||
res=dec2f(str);
|
||||
res = dec2f(str);
|
||||
}
|
||||
return negative?-res:res;
|
||||
return negative? -res:res;
|
||||
}
|
||||
|
||||
i32 utf8_hdchk(const char head) {
|
||||
// RFC-2279 but now we use RFC-3629 so nbytes is less than 4
|
||||
const u8 c=(u8)head;
|
||||
const u8 c = (u8)head;
|
||||
if ((c>>5)==0x06) { // 110x xxxx (10xx xxxx)^1
|
||||
return 1;
|
||||
}
|
||||
|
@ -195,36 +195,36 @@ i32 utf8_hdchk(const char head) {
|
|||
}
|
||||
|
||||
std::string chrhex(const char c) {
|
||||
const char hextbl[]="0123456789abcdef";
|
||||
return {hextbl[(c&0xf0)>>4],hextbl[c&0x0f]};
|
||||
const char hextbl[] = "0123456789abcdef";
|
||||
return {hextbl[(c&0xf0)>>4], hextbl[c&0x0f]};
|
||||
}
|
||||
|
||||
std::string rawstr(const std::string& str, const usize maxlen) {
|
||||
std::string ret("");
|
||||
for(auto i:str) {
|
||||
for(auto i : str) {
|
||||
// windows doesn't output unicode normally, so we output the hex
|
||||
if (is_windows() && i<=0) {
|
||||
ret+="\\x"+chrhex(i);
|
||||
ret += "\\x"+chrhex(i);
|
||||
continue;
|
||||
}
|
||||
switch(i) {
|
||||
case '\0': ret+="\\0"; break;
|
||||
case '\a': ret+="\\a"; break;
|
||||
case '\b': ret+="\\b"; break;
|
||||
case '\t': ret+="\\t"; break;
|
||||
case '\n': ret+="\\n"; break;
|
||||
case '\v': ret+="\\v"; break;
|
||||
case '\f': ret+="\\f"; break;
|
||||
case '\r': ret+="\\r"; break;
|
||||
case '\033':ret+="\\e"; break;
|
||||
case '\"': ret+="\\\"";break;
|
||||
case '\'': ret+="\\\'";break;
|
||||
case '\\': ret+="\\\\";break;
|
||||
default: ret+=i; break;
|
||||
case '\0': ret += "\\0"; break;
|
||||
case '\a': ret += "\\a"; break;
|
||||
case '\b': ret += "\\b"; break;
|
||||
case '\t': ret += "\\t"; break;
|
||||
case '\n': ret += "\\n"; break;
|
||||
case '\v': ret += "\\v"; break;
|
||||
case '\f': ret += "\\f"; break;
|
||||
case '\r': ret += "\\r"; break;
|
||||
case '\033':ret += "\\e"; break;
|
||||
case '\"': ret += "\\\""; break;
|
||||
case '\'': ret += "\\\'"; break;
|
||||
case '\\': ret += "\\\\"; break;
|
||||
default: ret += i; break;
|
||||
}
|
||||
}
|
||||
if (maxlen && ret.length()>maxlen) {
|
||||
ret=ret.substr(0,maxlen)+"...";
|
||||
ret = ret.substr(0,maxlen)+"...";
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -8,26 +8,28 @@ void vm::init(
|
|||
const std::vector<std::string>& filenames,
|
||||
const std::vector<std::string>& argv
|
||||
) {
|
||||
cnum=nums.data();
|
||||
cstr=strs.data();
|
||||
bytecode=code.data();
|
||||
files=filenames.data();
|
||||
cnum = nums.data();
|
||||
cstr = strs.data();
|
||||
bytecode = code.data();
|
||||
files = filenames.data();
|
||||
|
||||
/* set canary and program counter */
|
||||
ctx.pc=0;
|
||||
ctx.localr=ctx.memr=nullptr;
|
||||
ctx.funcr=ctx.upvalr=nil;
|
||||
ctx.canary=stack+STACK_DEPTH-1; // stack[STACK_DEPTH-1]
|
||||
ctx.top=stack;
|
||||
ctx.stack=stack;
|
||||
ctx.pc = 0;
|
||||
ctx.localr = nullptr;
|
||||
ctx.memr = nullptr;
|
||||
ctx.funcr = nil;
|
||||
ctx.upvalr = nil;
|
||||
ctx.canary = stack+STACK_DEPTH-1; // stack[STACK_DEPTH-1]
|
||||
ctx.top = stack;
|
||||
ctx.stack = stack;
|
||||
|
||||
/* clear main stack */
|
||||
for(u32 i=0;i<STACK_DEPTH;++i) {
|
||||
stack[i]=nil;
|
||||
for(u32 i = 0; i<STACK_DEPTH; ++i) {
|
||||
stack[i] = nil;
|
||||
}
|
||||
|
||||
/* init gc */
|
||||
ngc.init(strs,argv);
|
||||
ngc.init(strs, argv);
|
||||
|
||||
/* init vm globals */
|
||||
auto map_instance = ngc.alloc(vm_map);
|
||||
|
@ -35,10 +37,15 @@ void vm::init(
|
|||
for(const auto& i : global) {
|
||||
map_instance.map().mapper[i.first] = stack+i.second;
|
||||
}
|
||||
|
||||
/* init vm arg */
|
||||
auto arg_instance = ngc.alloc(vm_vec);
|
||||
stack[global.at("arg")] = arg_instance;
|
||||
arg_instance.vec().elems = ngc.env_argv;
|
||||
}
|
||||
|
||||
void vm::valinfo(var& val) {
|
||||
const nas_val* p=val.val.gcobj;
|
||||
const nas_val* p = val.val.gcobj;
|
||||
switch(val.type) {
|
||||
case vm_none: std::clog<<"| null |";break;
|
||||
case vm_ret: std::clog<<"| pc | 0x"<<std::hex
|
||||
|
@ -49,7 +56,8 @@ void vm::valinfo(var& val) {
|
|||
case vm_nil: std::clog<<"| nil |";break;
|
||||
case vm_num: std::clog<<"| num | "<<val.num();break;
|
||||
case vm_str: std::clog<<"| str | <0x"<<std::hex<<(u64)p
|
||||
<<"> "<<rawstr(val.str(),16)<<std::dec;break;
|
||||
<<"> "<<rawstr(val.str(),16)
|
||||
<<std::dec;break;
|
||||
case vm_func: std::clog<<"| func | <0x"<<std::hex<<(u64)p
|
||||
<<"> entry:0x"<<val.func().entry
|
||||
<<std::dec;break;
|
||||
|
|
|
@ -322,6 +322,19 @@ inline void vm::o_sub() {op_calc(-);}
|
|||
inline void vm::o_mul() {op_calc(*);}
|
||||
inline void vm::o_div() {op_calc(/);}
|
||||
inline void vm::o_lnk() {
|
||||
if (ctx.top[-1].type==vm_vec && ctx.top[0].type==vm_vec) {
|
||||
ngc.temp = ngc.alloc(vm_vec);
|
||||
for(auto i : ctx.top[-1].vec().elems) {
|
||||
ngc.temp.vec().elems.push_back(i);
|
||||
}
|
||||
for(auto i : ctx.top[0].vec().elems) {
|
||||
ngc.temp.vec().elems.push_back(i);
|
||||
}
|
||||
ctx.top[-1] = ngc.temp;
|
||||
ngc.temp = nil;
|
||||
--ctx.top;
|
||||
return;
|
||||
}
|
||||
ctx.top[-1] = ngc.newstr(ctx.top[-1].tostr()+ctx.top[0].tostr());
|
||||
--ctx.top;
|
||||
}
|
||||
|
@ -622,9 +635,12 @@ inline void vm::o_callfv() {
|
|||
return;
|
||||
}
|
||||
auto& func = local[-1].func();
|
||||
|
||||
// swap funcr with local[-1]
|
||||
var tmp = local[-1];
|
||||
local[-1] = ctx.funcr;
|
||||
ctx.funcr=tmp;
|
||||
ctx.funcr = tmp;
|
||||
|
||||
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
|
||||
if (ctx.top-argc+func.lsize+3>=ctx.canary) {
|
||||
die("stack overflow");
|
||||
|
@ -640,14 +656,14 @@ inline void vm::o_callfv() {
|
|||
var dynamic = nil;
|
||||
if (func.dpara>=0) { // load dynamic arguments
|
||||
dynamic = ngc.alloc(vm_vec);
|
||||
for(u32 i=psize;i<argc;++i) {
|
||||
for(u32 i = psize; i<argc; ++i) {
|
||||
dynamic.vec().elems.push_back(local[i]);
|
||||
}
|
||||
} else if (psize<argc) {
|
||||
// load arguments to "arg", located at stack+1
|
||||
stack[1] = ngc.alloc(vm_vec);
|
||||
for(u32 i=psize;i<argc;++i) {
|
||||
stack[1].vec().elems.push_back(local[i]);
|
||||
dynamic = ngc.alloc(vm_vec);
|
||||
for(u32 i = psize; i<argc; ++i) {
|
||||
dynamic.vec().elems.push_back(local[i]);
|
||||
}
|
||||
}
|
||||
// should reset stack top after allocating vector
|
||||
|
@ -658,22 +674,21 @@ inline void vm::o_callfv() {
|
|||
ctx.top = local+func.lsize;
|
||||
|
||||
u32 min_size = (std::min)(psize, argc); // avoid error in MSVC
|
||||
for(u32 i=min_size;i>=1;--i) { // load arguments
|
||||
for(u32 i = min_size; i>=1; --i) { // load arguments
|
||||
local[i] = local[i-1];
|
||||
}
|
||||
local[0] = func.local[0];// load "me"
|
||||
|
||||
// load local scope & default arguments
|
||||
for(u32 i=min_size+1;i<func.lsize;++i) {
|
||||
for(u32 i = min_size+1; i<func.lsize; ++i) {
|
||||
local[i] = func.local[i];
|
||||
}
|
||||
if (func.dpara>=0) {
|
||||
local[psize+1] = dynamic;
|
||||
}
|
||||
local[func.dpara>=0? psize+1:func.lsize-1] = dynamic;
|
||||
|
||||
ctx.top[0] = ctx.upvalr;
|
||||
(++ctx.top)[0] = var::addr(ctx.localr);
|
||||
(++ctx.top)[0] = var::ret(ctx.pc);
|
||||
ctx.pc=func.entry-1;
|
||||
ctx.pc = func.entry-1;
|
||||
ctx.localr = local;
|
||||
ctx.upvalr = nil;
|
||||
}
|
||||
|
@ -912,9 +927,6 @@ inline void vm::o_ret() {
|
|||
ctx.funcr = ctx.top[0];
|
||||
ctx.top[0] = ret; // rewrite func with returned value
|
||||
|
||||
// reset "arg"
|
||||
stack[1] = nil;
|
||||
|
||||
if (up.type==vm_upval) { // synchronize upvalue
|
||||
auto& upval = up.upval();
|
||||
auto size = func.func().lsize;
|
||||
|
|
|
@ -478,7 +478,7 @@ var os = {
|
|||
# runtime gives us some functions that we could manage it manually.
|
||||
var runtime = {
|
||||
# command line arguments
|
||||
argv: func() {return __sysargv;},
|
||||
argv: func() {return globals.arg;},
|
||||
gc: {
|
||||
extend: func(type) {return __gcextd;}
|
||||
}
|
||||
|
|
|
@ -45,12 +45,12 @@ var var_sort=func(){
|
|||
j-=1;
|
||||
}
|
||||
vec[i]=tmp;
|
||||
quick_sort_core(vec,left,i-1,cmp);
|
||||
quick_sort_core(vec,i+1,right,cmp);
|
||||
quick_sort_core(vec,left,i-1);
|
||||
quick_sort_core(vec,i+1,right);
|
||||
return nil;
|
||||
}
|
||||
return func(vec){
|
||||
quick_sort_core(vec,0,size(vec)-1,cmp);
|
||||
quick_sort_core(vec,0,size(vec)-1);
|
||||
return nil;
|
||||
}
|
||||
}();
|
|
@ -16,9 +16,22 @@ globals.test_func();
|
|||
|
||||
var f = func() {
|
||||
println(arg);
|
||||
func() {println(arg);}(114, 514, 1919, 810);
|
||||
println(arg);
|
||||
}
|
||||
|
||||
f(1, 2, 3);
|
||||
|
||||
var a = func(arg, b) {
|
||||
println(arg, " ", b);
|
||||
}
|
||||
var b = func(a) {
|
||||
println(a, " ", arg);
|
||||
}
|
||||
|
||||
a(1, 2, 3, 4); # 1 2
|
||||
b(1, 2, 3, 4); # 1 [2 3 4]
|
||||
|
||||
# command line arguments
|
||||
println(arg);
|
||||
println(globals.arg);
|
|
@ -1,9 +1,10 @@
|
|||
import.std.sort;
|
||||
|
||||
var vec=[];
|
||||
setsize(vec, 1e4);
|
||||
rand(time(0));
|
||||
for(var i=0;i<1e4;i+=1)
|
||||
append(vec,int(rand()*1e5));
|
||||
vec[i] = int(rand()*1e5);
|
||||
sort(vec);
|
||||
for(var i=1;i<1e4;i+=1) {
|
||||
if (vec[i]<vec[i-1]) {
|
||||
|
@ -20,7 +21,7 @@ var test=func(n){
|
|||
var ts=maketimestamp();
|
||||
ts.stamp();
|
||||
var_sort(a);
|
||||
println("[time] ",str(n)," in ",ts.elapsedMSec()/1000," sec (value)");
|
||||
println("[time] ",str(n)," in ",ts.elapsedMSec()/1000," sec (direct cmp)");
|
||||
|
||||
var a=[];
|
||||
setsize(a,n);
|
||||
|
@ -29,7 +30,7 @@ var test=func(n){
|
|||
}
|
||||
ts.stamp();
|
||||
sort(a);
|
||||
println("[time] ",str(n)," in ",ts.elapsedMSec()/1000," sec (lambda)");
|
||||
println("[time] ",str(n)," in ",ts.elapsedMSec()/1000," sec (lambda cmp)");
|
||||
}
|
||||
|
||||
for(var i=1000;i<1e6;i*=10){
|
||||
|
|
131
test/sample.nas
131
test/sample.nas
|
@ -1,16 +1,16 @@
|
|||
# This file is written by Andy Ross, and is protected by GPLv2.0
|
||||
|
||||
# A no-op function used below to get this file to run. Ignore and read on...
|
||||
dummyFunc = func { 1 }
|
||||
var dummyFunc = func { 1 }
|
||||
|
||||
#
|
||||
# Literal numbers can be decimal, exponential, or hex constants. All
|
||||
# numbers are stored internally as IEEE double-precision values.
|
||||
#
|
||||
n1 = 3;
|
||||
n2 = 3.14;
|
||||
n3 = 6.023e23;
|
||||
n3 = 0x123456;
|
||||
var n1 = 3;
|
||||
var n2 = 3.14;
|
||||
var n3 = 6.023e23;
|
||||
var n3 = 0x123456;
|
||||
|
||||
#
|
||||
# Two identical string literals with different quotes. Double quotes
|
||||
|
@ -19,14 +19,14 @@ n3 = 0x123456;
|
|||
# whitespace like newlines). Double quotes handle the following
|
||||
# C-like escapes: \n \r \t \xnn \"
|
||||
#
|
||||
s1 = 'Andy\'s "computer" has a C:\righteous\newstuff directory.';
|
||||
s2 = "Andy's \"computer\" has a C:\\righteous\\newstuff directory.";
|
||||
var s1 = 'Andy\'s "computer" has a C:\righteous\newstuff directory.';
|
||||
var s2 = "Andy's \"computer\" has a C:\\righteous\\newstuff directory.";
|
||||
|
||||
#
|
||||
# Literal lists use square brackets with a comma-separated expression
|
||||
# list.
|
||||
#
|
||||
list1 = ["a", "b", 1, 2];
|
||||
var list1 = ["a", "b", 1, 2];
|
||||
|
||||
#
|
||||
# Literal hashes (or objects -- same thing) use curlies and colons to
|
||||
|
@ -35,8 +35,8 @@ list1 = ["a", "b", 1, 2];
|
|||
# to use symbols, lookup tables of other types will be more
|
||||
# comfortable with literals.
|
||||
#
|
||||
hash1 = { name : "Andy", job : "Hacker" };
|
||||
EnglishEspanol = { "one" : "uno", "two": "dos", "blue" : "azul" };
|
||||
var hash1 = { name : "Andy", job : "Hacker" };
|
||||
var EnglishEspanol = { "one" : "uno", "two": "dos", "blue" : "azul" };
|
||||
|
||||
#
|
||||
# Both vectors and hashes use square brackets for the lookup operation:
|
||||
|
@ -50,7 +50,7 @@ hash1["name"] == "Andy";
|
|||
# (anonymous) function argument to the local "log_message" variable.
|
||||
# There is no function declaration syntax in Nasal.
|
||||
#
|
||||
log_message = func {
|
||||
var log_message = func {
|
||||
print(arg[0]);
|
||||
}
|
||||
|
||||
|
@ -58,10 +58,10 @@ log_message = func {
|
|||
# You can also pass named arguments to a function, thus saving the
|
||||
# typing and performance costs of extracting them from the arg array.
|
||||
#
|
||||
sqrt = dummyFunc;
|
||||
dist = func(x1, y1, x2, y2) {
|
||||
dx = x2-x1;
|
||||
dy = y2-y1;
|
||||
var sqrt = dummyFunc;
|
||||
var dist = func(x1, y1, x2, y2) {
|
||||
var dx = x2-x1;
|
||||
var dy = y2-y1;
|
||||
return sqrt(dx*dx + dy*dy);
|
||||
}
|
||||
dist(0,0,1,1); # == sqrt(2)
|
||||
|
@ -71,14 +71,14 @@ dist(0,0,1,1); # == sqrt(2)
|
|||
# default value must be a scalar (number, string, function, nil) and
|
||||
# not a mutable composite object (list, hash).
|
||||
#
|
||||
read = func(bytes, flags=0) { }
|
||||
var read = func(bytes, flags=0) { }
|
||||
|
||||
#
|
||||
# Any extra arguments after the named list are placed in the "arg"
|
||||
# vector as above. You can rename this to something other than "arg"
|
||||
# by specifying a final argument name with an ellipsis:
|
||||
#
|
||||
listify = func(elements...) { return elements; }
|
||||
var listify = func(elements...) { return elements; }
|
||||
listify(1, 2, 3, 4); # returns a list: [1, 2, 3, 4]
|
||||
|
||||
#
|
||||
|
@ -87,7 +87,7 @@ listify(1, 2, 3, 4); # returns a list: [1, 2, 3, 4]
|
|||
# good practice in general, although it is not required. Note that
|
||||
# this is not a "declaration", just a qualifier on the "=" operator.
|
||||
#
|
||||
innerFunc = func {
|
||||
var innerFunc = func {
|
||||
for(var dist=0; dist<100; dist += 1) {
|
||||
# Does not interfere with the "dist" symbol defined above
|
||||
}
|
||||
|
@ -99,26 +99,26 @@ innerFunc = func {
|
|||
# what the ?: does in C. The last semicolon in a code block is
|
||||
# optional, to make this prettier.
|
||||
#
|
||||
abs = func(n) { if(n<0) { -n } else { n } }
|
||||
var abs = func(n) { if(n<0) { -n } else { n } }
|
||||
|
||||
#
|
||||
# But for those who don't like typing, the ternary operator works like
|
||||
# you expect:
|
||||
#
|
||||
abs = func(n) { n < 0 ? -n : n }
|
||||
var abs = func(n) { n < 0 ? -n : n }
|
||||
|
||||
#
|
||||
# Nasal supports a "nil" value for use as a null pointer equivalent.
|
||||
# It can be tested for equality, matching only other nils.
|
||||
#
|
||||
listNode = { data : ["what", "ever"], next : nil };
|
||||
var listNode = { data : ["what", "ever"], next : nil };
|
||||
|
||||
#
|
||||
# Nasal's binary boolean operators are "and" and "or", unlike C.
|
||||
# unary not is still "!" however. They short-circuit like you expect
|
||||
#
|
||||
toggle = 0;
|
||||
a = nil;
|
||||
var toggle = 0;
|
||||
var a = nil;
|
||||
if(a and a.field == 42) {
|
||||
toggle = !toggle; # doesn't crash when a is nil
|
||||
}
|
||||
|
@ -129,24 +129,24 @@ if(a and a.field == 42) {
|
|||
# takes a local variable name as its first argument and a vector as
|
||||
# its second.
|
||||
#
|
||||
doSomething = dummyFunc;
|
||||
var doSomething = dummyFunc;
|
||||
|
||||
stillGoing = 0;
|
||||
var stillGoing = 0;
|
||||
while(stillGoing) { doSomething(); }
|
||||
|
||||
for(i=0; i < 3; i = i+1) {
|
||||
for(var i=0; i < 3; i = i+1) {
|
||||
elem = list1[i];
|
||||
doSomething(elem);
|
||||
}
|
||||
|
||||
foreach(elem; list1) { doSomething(elem) } # Shorthand for above
|
||||
foreach(var elem; list1) { doSomething(elem) } # Shorthand for above
|
||||
|
||||
#
|
||||
# There is also a "forindex", which is like foreach except that it
|
||||
# assigns the index of each element, instead of the value, to the loop
|
||||
# variable.
|
||||
#
|
||||
forindex(i; list1) { doSomething(list1[i]); }
|
||||
forindex(var i; list1) { doSomething(list1[i]); }
|
||||
|
||||
#
|
||||
# Define a class object with one method, one field and one "new"
|
||||
|
@ -155,10 +155,10 @@ forindex(i; list1) { doSomething(list1[i]); }
|
|||
# appropriately. Member functions can get their local object (the
|
||||
# equivalent of the "this" pointer in C++) as the "me" variable.
|
||||
#
|
||||
Class1 = {};
|
||||
var Class1 = {};
|
||||
|
||||
Class1.new = func {
|
||||
obj = { parents : [Class1],
|
||||
var obj = { parents : [Class1],
|
||||
count : 0 };
|
||||
return obj;
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ Class1.getcount = func {
|
|||
return me.count;
|
||||
}
|
||||
|
||||
c = Class1.new();
|
||||
var c = Class1.new();
|
||||
print(c.getcount(), "\n"); # prints 1
|
||||
print(c.getcount(), "\n"); # prints 2
|
||||
print(c.getcount(), "\n"); # prints 3
|
||||
|
@ -177,20 +177,20 @@ print(c.getcount(), "\n"); # prints 3
|
|||
# But *set* operations always go to the local object. You can't
|
||||
# corrupt a parent class via OOP operations on its instances (but you
|
||||
# *can* get to it via hand-inspection of the parents arrays).
|
||||
c2 = Class1.new();
|
||||
c2.getcount() = func { 12345 }; # custom "derived" function!
|
||||
var c2 = Class1.new();
|
||||
c2.getcount = func { return 12345 }; # custom "derived" function!
|
||||
|
||||
print(c2.getcount(), "\n"); # prints 12345
|
||||
print(c1.getcount(), "\n"); # prints 4, Class1.getcount is unchanged
|
||||
print(c.getcount(), "\n"); # prints 4, Class1.getcount is unchanged
|
||||
|
||||
#
|
||||
# This creates an identical class using alternative syntax.
|
||||
#
|
||||
Class2 = {
|
||||
var Class2 = {
|
||||
new : func {
|
||||
obj = {};
|
||||
obj.parents = [Class2];
|
||||
obj.count = 0;
|
||||
var obj = {};
|
||||
obj.parents = [Class2];
|
||||
obj.count = 0;
|
||||
return obj;
|
||||
},
|
||||
getcount : func {
|
||||
|
@ -206,7 +206,7 @@ Class2 = {
|
|||
# C (although note that there is no nul termination -- get the length
|
||||
# with size()):
|
||||
#
|
||||
string = "abcdefghijklmnopqrstuvwxyz";
|
||||
var string = "abcdefghijklmnopqrstuvwxyz";
|
||||
var ascii_sum = 0;
|
||||
for(var i=0; i<size(string); i+=1) { ascii_sum += string[i]; }
|
||||
|
||||
|
@ -222,7 +222,7 @@ if(`©` != 169) { print("Unicode violation bug!\n"); }
|
|||
# can make a mutable string either with the append operator or the
|
||||
# bits.buf() function.
|
||||
#
|
||||
ascii_lc = func(string) {
|
||||
var ascii_lc = func(string) {
|
||||
var mutable = string ~ "";
|
||||
for(var i=0; i<size(mutable); i+=1) {
|
||||
if(mutable[i] >= `A` and mutable[i] <= `Z`) {
|
||||
|
@ -237,14 +237,15 @@ 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];
|
||||
var 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];
|
||||
var joined_list = [1, 2, 3] ~ [4, 5, 6];
|
||||
print(joined_list, "\n");
|
||||
|
||||
###
|
||||
### Now some fun examples:
|
||||
|
@ -254,9 +255,9 @@ joined_list = [1, 2, 3] ~ [4, 5, 6];
|
|||
# Make a "inverted index" hash out of a vector that returns the index
|
||||
# for each element.
|
||||
#
|
||||
invert = func(vec) {
|
||||
hash = {};
|
||||
for(i=0; i<size(vec); i = i+1) {
|
||||
var invert = func(vec) {
|
||||
var hash = {};
|
||||
for(var i=0; i<size(vec); i = i+1) {
|
||||
hash[vec[i]] = i;
|
||||
}
|
||||
return hash;
|
||||
|
@ -266,16 +267,16 @@ invert = func(vec) {
|
|||
# Use the return value of the above function to do an "index of"
|
||||
# lookup on a vector
|
||||
#
|
||||
vecfind = func(vec, elem) { return invert(vec)[elem]; }
|
||||
var vecfind = func(vec, elem) { return invert(vec)[elem]; }
|
||||
|
||||
#
|
||||
# Joins its arguments with the empty string and returns a scalar.
|
||||
# Note use of "~" operator to do string concatenation (Nasal's only
|
||||
# funny syntax).
|
||||
#
|
||||
join = func {
|
||||
s = "";
|
||||
foreach(elem; arg) { s = s ~ elem; }
|
||||
var join = func {
|
||||
var s = "";
|
||||
foreach(var elem; arg) { s = s ~ elem; }
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -283,14 +284,16 @@ join = func {
|
|||
# Labeled break/continue syntax puts the label in as an extra first
|
||||
# argument to the for/while/foreach.
|
||||
#
|
||||
doneWithInnerLoopEarly = dummyFunc;
|
||||
completelyDone = dummyFunc;
|
||||
for(OUTER; i=0; i<100; i = i+1) {
|
||||
for(j=0; j<100; j = j+1) {
|
||||
var doneWithInnerLoopEarly = dummyFunc;
|
||||
var completelyDone = dummyFunc;
|
||||
# not supported now
|
||||
for(#OUTER;
|
||||
var i=0; i<100; i = i+1) {
|
||||
for(var j=0; j<100; j = j+1) {
|
||||
if(doneWithInnerLoopEarly()) {
|
||||
break;
|
||||
} elsif(completelyDone()) {
|
||||
break OUTER;
|
||||
break #OUTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -303,10 +306,10 @@ for(OUTER; i=0; i<100; i = i+1) {
|
|||
## also makes no attempt to escape special characters in strings, which
|
||||
## can break re-parsing in strange (and possibly insecure!) ways.
|
||||
##
|
||||
dump = func(o) {
|
||||
result = "";
|
||||
var dump = func(o) {
|
||||
var result = "";
|
||||
if(typeof(o) == "scalar") {
|
||||
n = num(o);
|
||||
var n = num(o);
|
||||
if(n == nil) { result = result ~ '"' ~ o ~ '"'; }
|
||||
else { result = result ~ o; }
|
||||
} elsif(typeof(o) == "vector") {
|
||||
|
@ -317,14 +320,14 @@ dump = func(o) {
|
|||
}
|
||||
result = result ~ " ]";
|
||||
} elsif(typeof(o) == "hash") {
|
||||
ks = keys(o);
|
||||
var ks = keys(o);
|
||||
result = result ~ "{ ";
|
||||
if(size(o) > 0) {
|
||||
k = ks[0];
|
||||
var k = ks[0];
|
||||
result = result ~ k ~ ":" ~ dump(o[k]);
|
||||
}
|
||||
for(i=1; i<size(o); i=i+1) {
|
||||
k = ks[i];
|
||||
var k = ks[i];
|
||||
result = result ~ ", " ~ k ~ " : " ~ dump(o[k]);
|
||||
}
|
||||
result = result ~ " }";
|
||||
|
@ -345,7 +348,7 @@ dump = func(o) {
|
|||
# normal function definition. Oh well, every language has a syntactic
|
||||
# quirk or two...)
|
||||
#
|
||||
a = (func(n){ n + 1 })(232); # "a" now equals 233
|
||||
var a = (func(n){ n + 1 })(232); # "a" now equals 233
|
||||
|
||||
#
|
||||
# Functional programming B. All expressions have a value, the last
|
||||
|
@ -354,7 +357,7 @@ a = (func(n){ n + 1 })(232); # "a" now equals 233
|
|||
# (assignment, duh) have side effects. e.g. The "if" expression works
|
||||
# both for code flow and as the ?: expression in C/C++.
|
||||
#
|
||||
factorial = func(n) { if(n == 0) { 1 }
|
||||
var factorial = func(n) { if(n == 0) { 1 }
|
||||
else { n * factorial(n-1) } }
|
||||
print(factorial(10), "\n");
|
||||
|
||||
|
@ -364,8 +367,8 @@ print(factorial(10), "\n");
|
|||
# local variables in the outer scope even after their creator has
|
||||
# returned.
|
||||
#
|
||||
getcounter = func { count = 0; return func { count = count + 1 } }
|
||||
mycounter = getcounter();
|
||||
var getcounter = func { var count = 0; return func { count = count + 1 } }
|
||||
var mycounter = getcounter();
|
||||
print(mycounter(), "\n"); # prints 1
|
||||
print(mycounter(), "\n"); # prints 2
|
||||
print(mycounter(), "\n"); # prints 3
|
||||
|
|
|
@ -229,3 +229,5 @@ for(var a=0;a<16;a+=1) {
|
|||
println("temp^=0x"~h[a]~" -> 0x",h[temp^=a]," temp&=0x"~h[a]~" -> 0x",h[temp&=a]," temp|=0x"~h[a]~" -> 0x",h[temp|=a]);
|
||||
}
|
||||
}
|
||||
|
||||
print([0, 1, 2]~[3, 4, 5], "\n");
|
Loading…
Reference in New Issue