From 7d8124669509b240aaa3479445f3ad7b649da20a Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 13 Aug 2023 00:31:11 +0800 Subject: [PATCH 01/15] :memo: optimize code format --- std/csv.nas | 12 +- std/file.nas | 109 ++++++++-------- std/json.nas | 331 ++++++++++++++++++++++++------------------------ std/padding.nas | 28 ++-- std/string.nas | 4 +- 5 files changed, 248 insertions(+), 236 deletions(-) diff --git a/std/csv.nas b/std/csv.nas index bf2e54a..94800a9 100644 --- a/std/csv.nas +++ b/std/csv.nas @@ -1,16 +1,16 @@ # lib csv.nas # ValKmjolnir 2022/10/15 -var read_csv=func(path,delimeter=",",endline="\n"){ - var context=io.readfile(path); - context=split(endline,context); +var read = func(path, delimeter=",", endline="\n"){ + var context = io.readfile(path); + context = split(endline, context); forindex(var i;context){ - context[i]=split(delimeter,context[i]); + context[i] = split(delimeter,context[i]); } if(size(context)<=1){ die("incorrect csv file <"~path~">: "~size(context)~" line(s)."); } return { - property:context[0], - data:context[1:] + property: context[0], + data: context[1:] }; } \ No newline at end of file diff --git a/std/file.nas b/std/file.nas index 7824c3e..4159561 100644 --- a/std/file.nas +++ b/std/file.nas @@ -1,78 +1,85 @@ # lib file.nas # ValKmjolnir 2022/3/6 -var file={ - SEEK_SET:io.SEEK_SET, - SEEK_CUR:io.SEEK_CUR, - SEEK_END:io.SEEK_END, - new: func(filename,mode="r"){ - if(!io.exists(filename)) - return nil; - var fd=io.open(filename,mode); - return { - close: func(){io.close(fd);}, - read: func(len){ - var buf=mut(""); - io.read(fd,buf,len); - return buf; - }, - write: func(str){return io.write(fd,str);}, - seek: func(pos,whence){return io.seek(fd,pos,whence);}, - tell: func(){return io.tell(fd);}, - readln: func(){return io.readln(fd);}, - stat: func(){return io.stat(filename);}, - eof: func(){return io.eof(fd);} - }; - } -}; -var find_all_files_with_extension=func(path,extensions...){ - var in_vec=func(ext){ - foreach(var i;extensions){ - if(ext==i){ +var SEEK_SET = io.SEEK_SET; + +var SEEK_CUR = io.SEEK_CUR; + +var SEEK_END = io.SEEK_END; + + +var new = func(filename, mode="r"){ + if (!io.exists(filename)) { + return nil; + } + var fd = io.open(filename, mode); + return { + close: func() {io.close(fd);}, + read: func(len) { + var buf = mut(""); + io.read(fd, buf, len); + return buf; + }, + write: func(str) {return io.write(fd, str);}, + seek: func(pos, whence) {return io.seek(fd, pos, whence);}, + tell: func() {return io.tell(fd);}, + readln: func() {return io.readln(fd);}, + stat: func() {return io.stat(filename);}, + eof: func() {return io.eof(fd);} + }; +} + +var find_all_files_with_extension = func(path, extensions...){ + var in_vec = func(ext) { + foreach(var i;extensions) { + if (ext==i){ return 1; } } return 0; } - var res=[]; + var res = []; foreach(var f;find_all_files(path)){ - var tmp=split('.',f); - if(size(tmp)>1 and in_vec(tmp[-1])){ - append(res,f); + var tmp = split('.', f); + if (size(tmp)>1 and in_vec(tmp[-1])) { + append(res, f); } } return res; } -var find_all_files=func(path){ - if(!io.exists(path)) +var find_all_files = func(path){ + if (!io.exists(path)) { return []; - var dd=unix.opendir(path); - var res=[]; - while(var n=unix.readdir(dd)) - if(unix.isfile(path~"/"~n)) - append(res,n); + } + var dd = unix.opendir(path); + var res = []; + while(var n = unix.readdir(dd)) + if(unix.isfile(path~"/"~n)) { + append(res, n); + } unix.closedir(dd); return res; } -var recursive_find_files=func(path){ - if(!io.exists(path)) +var recursive_find_files = func(path) { + if (!io.exists(path)) { return nil; - var dd=unix.opendir(path); - var res={ - dir:path, - files:[] + } + var dd = unix.opendir(path); + var res = { + dir: path, + files: [] }; - while(var n=unix.readdir(dd)){ - if(unix.isfile(path~"/"~n)){ + while(var n = unix.readdir(dd)) { + if (unix.isfile(path~"/"~n)) { append(res.files,n); - }elsif(unix.isdir(path~"/"~n) and n!="." and n!=".."){ - var tmp=recursive_find_files(path~"/"~n); - if(tmp!=nil) + } elsif (unix.isdir(path~"/"~n) and n!="." and n!="..") { + var tmp = recursive_find_files(path~"/"~n); + if (tmp!=nil) { append(res.files,tmp); + } } - } unix.closedir(dd); return res; diff --git a/std/json.nas b/std/json.nas index 145ca01..e2ff68a 100644 --- a/std/json.nas +++ b/std/json.nas @@ -1,59 +1,59 @@ # lib json.nas # 2021 ValKmjolnir -var JSON=func() { - var ( - j_eof, - j_lbrace, - j_rbrace, - j_lbrkt, - j_rbrkt, - j_comma, - j_colon, - j_str, - j_num, - j_id - )=(0,1,2,3,4,5,6,7,8,9); - var j_content=[ - "eof", - "`{`", - "`}`", - "`[`", - "`]`", - "`,`", - "`:`", - "string", - "number", - "identifier" - ]; +var ( + _j_eof, _j_lbrace, _j_rbrace, _j_lbrkt, _j_rbrkt, + _j_comma, _j_colon, _j_str, _j_num, _j_id +) = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); - var text=''; - var line=1; - var text_size=0; - var ptr=0; - var token={content:'',type:''}; +var _j_content = [ + "eof", + "`{`", + "`}`", + "`[`", + "`]`", + "`,`", + "`:`", + "string", + "number", + "identifier" +]; - var init=func() { - text=''; - line=1; - text_size=0; - ptr=0; - token={content:'',type:''}; +var JSON = func() { + + var text = ""; + var line = 1; + var text_size = 0; + var ptr = 0; + var token = { + content: "", + type: "" + }; + + var init = func() { + text = ""; + line = 1; + text_size = 0; + ptr = 0; + token = { + content: "", + type: "" + }; } - var isnum=func(c) { + var isnum = func(c) { return '0'<=c and c<='9'; } - var isid=func(c) { - var tmp=c[0]; + var isid = func(c) { + var tmp = c[0]; return ('a'[0]<=tmp and tmp<='z'[0]) or - ('A'[0]<=tmp and tmp<='Z'[0]) or - c=='_'; + ('A'[0]<=tmp and tmp<='Z'[0]) or + c=='_'; } - var check=func() { - var c=char(text[ptr]); + var check = func() { + var c = char(text[ptr]); return ( c=='{' or c=='}' or c=='[' or c==']' or @@ -63,151 +63,152 @@ var JSON=func() { ); } - var get=func(str) { + var get = func(str) { init(); - if(!size(str)) { + if (!size(str)) { println("JSON.parse: empty string"); - str="[]"; + str = "[]"; } - text=str; - text_size=size(text); + text = str; + text_size = size(text); return; } - var next=func() { + var next = func() { while(ptr=text_size) { - token.content="eof"; - token.type=j_eof; + token.content = "eof"; + token.type = _j_eof; return; } - var c=char(text[ptr]); - if(c=='{') { - token.content='{'; - token.type=j_lbrace; - } elsif(c=='}') { - token.content='}'; - token.type=j_rbrace; - } elsif(c=='[') { - token.content='['; - token.type=j_lbrkt; - } elsif(c==']') { - token.content=']'; - token.type=j_rbrkt; - } elsif(c==',') { - token.content=','; - token.type=j_comma; - } elsif(c==':') { - token.content=':'; - token.type=j_colon; - } elsif(c=='\"' or c=='\'') { - var strbegin=c; - var s=""; - ptr+=1; + var c = char(text[ptr]); + if (c=='{') { + token.content = '{'; + token.type = _j_lbrace; + } elsif (c=='}') { + token.content = '}'; + token.type = _j_rbrace; + } elsif (c=='[') { + token.content = '['; + token.type = _j_lbrkt; + } elsif (c==']') { + token.content = ']'; + token.type = _j_rbrkt; + } elsif (c==',') { + token.content = ','; + token.type = _j_comma; + } elsif (c==':') { + token.content = ':'; + token.type = _j_colon; + } elsif (c=='\"' or c=='\'') { + var strbegin = c; + var s = ""; + ptr += 1; while(ptr Date: Sun, 13 Aug 2023 22:12:07 +0800 Subject: [PATCH 02/15] :sparkles: add check for symbol definition --- src/nasal_codegen.cpp | 11 ++- src/nasal_gc.cpp | 12 ++- src/symbol_finder.cpp | 7 +- src/symbol_finder.h | 2 +- std/props.nas | 193 +++++++++++++++++++++++++++++++++--------- 5 files changed, 177 insertions(+), 48 deletions(-) diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 8e41af7..28477c8 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -75,11 +75,14 @@ void codegen::regist_str(const std::string& str) { void codegen::find_symbol(code_block* node) { auto finder = std::unique_ptr(new symbol_finder); for(const auto& i : finder->do_find(node)) { - if (!experimental_namespace.count(i.file)) { - experimental_namespace[i.file] = {}; + if (native_function_mapper.count(i.name)) { + die("definition conflicts with native function", i.location); } - if (local.empty() && !experimental_namespace.at(i.file).count(i.name)) { - experimental_namespace.at(i.file).insert(i.name); + if (!experimental_namespace.count(i.location.file)) { + experimental_namespace[i.location.file] = {}; + } + if (local.empty() && !experimental_namespace.at(i.location.file).count(i.name)) { + experimental_namespace.at(i.location.file).insert(i.name); } add_symbol(i.name); } diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index 4523adf..ee6b1e2 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -107,9 +107,19 @@ void nas_ghost::set( } void nas_ghost::clear() { - if (!ptr || !dtor_ptr) { + // do nothing if pointer is null + if (!ptr) { return; } + + // do clear pointer if destructor function pointer is null + if (!dtor_ptr) { + type_name = ""; + ptr = nullptr; + return; + } + + // do destruction dtor_ptr(ptr); type_name = ""; ptr = nullptr; diff --git a/src/symbol_finder.cpp b/src/symbol_finder.cpp index 58a84fe..7f34a55 100644 --- a/src/symbol_finder.cpp +++ b/src/symbol_finder.cpp @@ -4,13 +4,13 @@ bool symbol_finder::visit_definition_expr(definition_expr* node) { if (node->get_variable_name()) { symbols.push_back({ node->get_variable_name()->get_name(), - node->get_variable_name()->get_location().file + node->get_variable_name()->get_location() }); } else { for(auto i : node->get_variables()->get_variables()) { symbols.push_back({ i->get_name(), - i->get_location().file + i->get_location() }); } } @@ -30,7 +30,8 @@ bool symbol_finder::visit_iter_expr(iter_expr* node) { if (node->get_name()) { symbols.push_back({ node->get_name()->get_name(), - node->get_name()->get_location().file}); + node->get_name()->get_location() + }); } return true; } diff --git a/src/symbol_finder.h b/src/symbol_finder.h index a0eb852..545e94e 100644 --- a/src/symbol_finder.h +++ b/src/symbol_finder.h @@ -11,7 +11,7 @@ class symbol_finder:public ast_visitor { public: struct symbol_info { std::string name; - std::string file; + span location; }; private: diff --git a/std/props.nas b/std/props.nas index c10c646..c9ba748 100644 --- a/std/props.nas +++ b/std/props.nas @@ -10,42 +10,152 @@ # available in C++; just use node.getNode(path).whatever() instead. # -# unfinished -var getprop = func {} -var fgcommand = func {} -var _globals = func {} -var _createCondition = func {} -var _new = func {} -var string = {}; -var _getNode = func {}; -var _getParent = func {}; -var _getChildren = func {}; -var _setChildren = func {}; -var _alias = func {}; -var _equals = func {}; -var _unalias = func {}; -var _adjustValue = func {}; -var _setDoubleValue = func {}; -var _setIntValue = func {}; -var _setBoolValue = func {}; -var _toggleBoolValue = func {}; -var _setValue = func {}; -var _setValues = func {}; -var _getAttribute = func {}; -var _setAttribute = func {}; -var _getValue = func {}; -var _getType = func {}; -var _isNumeric = func {}; -var _isInt = func {}; -var _getIndex = func {}; -var _getName = func {}; -var _getAliasTarget = func {}; -var _getChild = func {}; -var _addChild = func {}; -var _addChildren = func {}; -var _removeChild = func {}; -var _removeChildren = func {}; -var _removeAllChildren = func {}; +var _new = func { + return { + type: "", + name: "", + value: nil, + parent_list:[], + child_list:[] + }; +} + +var _fg_props_globals = _new(); +var _globals = func { + return _fg_props_globals; +} + +var getprop = func(arg...) { + die("unimplemented"); +} + +var addcommand = func(name, code) { + die("unimplemented"); +} + +var fgcommand = func(name, args = nil) { + die("unimplemented"); +} + +var _createCondition = func { + die("unimplemented"); +} + +var _getNode = func { + die("unimplemented"); +}; + +var _getParent = func { + die("unimplemented"); +}; + +var _getChildren = func { + die("unimplemented"); +}; + +var _setChildren = func { + die("unimplemented"); +}; + +var _alias = func { + die("unimplemented"); +}; + +var _equals = func { + die("unimplemented"); +}; + +var _unalias = func { + die("unimplemented"); +}; + +var _adjustValue = func { + die("unimplemented"); +}; + +var _setDoubleValue = func { + die("unimplemented"); +}; + +var _setIntValue = func { + die("unimplemented"); +}; + +var _setBoolValue = func { + die("unimplemented"); +}; + +var _toggleBoolValue = func { + die("unimplemented"); +}; + +var _setValue = func { + die("unimplemented"); +}; + +var _setValues = func { + die("unimplemented"); +}; + +var _getAttribute = func { + die("unimplemented"); +}; + +var _setAttribute = func { + die("unimplemented"); +}; + +var _getValue = func { + die("unimplemented"); +}; + +var _getType = func { + die("unimplemented"); +}; + +var _isNumeric = func { + die("unimplemented"); +}; + +var _isInt = func { + die("unimplemented"); +}; + +var _getIndex = func { + die("unimplemented"); +}; + +var _getName = func { + die("unimplemented"); +}; + +var _getAliasTarget = func { + die("unimplemented"); +}; + +var _getChild = func { + die("unimplemented"); +}; + +var _addChild = func { + die("unimplemented"); +}; + +var _addChildren = func { + die("unimplemented"); +}; + +var _removeChild = func { + die("unimplemented"); +}; + +var _removeChildren = func { + die("unimplemented"); +}; + +var _removeAllChildren = func { + die("unimplemented"); +}; var Node = { @@ -190,8 +300,9 @@ var Node = { # Node.new = func(values = nil) { var result = wrapNode(_new()); - if(ishash(values)) + if(ishash(values)) { result.setValues(values); + } return result; } @@ -331,14 +442,18 @@ var wrap = func(node) { # Node object and its _g (ghost) field set to the specified object. # Nasal's literal syntax can be pleasingly terse. I like that. :) # -var wrapNode = func(node) { { parents : [Node], _g : node } } +var wrapNode = func(node) { + return { parents : [Node], _g : node }; +} ## # Global property tree. Set once at initialization. Is that OK? # Does anything ever call globals.set_props() from C++? May need to # turn this into a function if so. # -var globals = wrapNode(_globals()); +var globals = func { + return wrapNode(_globals()); +}(); ## # Shortcut for props.globals.getNode(). From 88b039a82e166de6ef4e31a60c42092156bf1330 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 19 Aug 2023 21:36:12 +0800 Subject: [PATCH 03/15] :memo: add experimental repl (for fun) --- .gitignore | 1 + tools/repl.nas | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tools/repl.nas diff --git a/.gitignore b/.gitignore index 5e477ca..7b57570 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ nasal.exe .vscode dump fgfs.log +.temp.* # build dir build diff --git a/tools/repl.nas b/tools/repl.nas new file mode 100644 index 0000000..78768c1 --- /dev/null +++ b/tools/repl.nas @@ -0,0 +1,72 @@ +# experimental repl +# 2023/8/19 by ValKmjolnir + +var help = func() { + println(" .help | show help"); + println(" .exit | quit the REPL"); + println(" .quit | quit the REPL"); + println(" .clear | clear the screen"); + println(); +} + +var content = []; +var log_cache = ""; + +println("Nasal: This is experimental REPL"); +help(); + +var count_bracket = func(line) { + var len = size(line); + var count = 0; + for(var i = 0; i < len; i += 1) { + if (line[i] == "{"[0]) { + count += 1; + } elsif (line[i] == "}"[0]) { + count -= 1; + } + } + return count; +} + +while(1) { + var line = readline(">>> "); + if (line == ".exit" or line == ".quit") { + break; + } elsif (line == ".help") { + println(); + help(); + continue; + } elsif (line == ".clear") { + print("\ec"); + continue; + } elsif (line[0] == "."[0]) { + println("no such command \"", line, "\", input \".help\" for help\n"); + continue; + } + var in_bracket_level = count_bracket(line); + while(in_bracket_level > 0) { + var temp_line = readline("... "); + in_bracket_level += count_bracket(temp_line); + line ~= temp_line ~ "\n"; + } + + append(content, line); + + var source = ""; + foreach(var i; content) { + source ~= i ~ ";\n"; + } + + io.fout(".temp.nas", source); + var result = system("nasal .temp.nas > .temp.log"); + if (result != 0) { + pop(content); + continue; + } + + var log = io.readfile(".temp.log"); + if (size(log) and size(log) != size(log_cache)) { + println(substr(log, size(log_cache), size(log)), "\n"); + log_cache = log; + } +} \ No newline at end of file From 98b0086656cf0ae4188e471475746bd7e08fb3d6 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 20 Aug 2023 16:48:53 +0800 Subject: [PATCH 04/15] :bug: fix segfault in `var x = (var a,b) = (1,2)` --- src/nasal_parse.cpp | 18 ++++++++++++++---- tools/repl.nas | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index ebfd397..e56e4e4 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -118,7 +118,11 @@ bool parse::check_tuple() { } bool parse::check_func_end(expr* node) { - auto type=node->get_type(); + // avoid error parse caused nullptr return value + if (!node) { + return true; + } + auto type = node->get_type(); if (type==expr_type::ast_func) { return true; } else if (type==expr_type::ast_def) { @@ -154,7 +158,11 @@ bool parse::check_special_call() { } bool parse::need_semi_check(expr* node) { - auto type=node->get_type(); + // avoid error parse caused nullptr return value + if (!node) { + return true; + } + auto type = node->get_type(); if (type==expr_type::ast_for || type==expr_type::ast_forei || type==expr_type::ast_while || @@ -348,7 +356,7 @@ expr* parse::expression() { case tok::cont: return continue_expression(); case tok::brk: return break_expression(); case tok::ret: return return_expression(); - case tok::semi: break; + case tok::semi: break; default: die(thisspan, "incorrect token <"+toks[ptr].str+">"); next(); @@ -627,7 +635,9 @@ expr* parse::scalar() { return null(); } // check call and avoid ambiguous syntax - if (is_call(toks[ptr].type) && !(lookahead(tok::lcurve) && toks[ptr+1].type==tok::var)) { + // i don't know why using `&& !(lookahead(tok::lcurve) && toks[ptr+1].type==tok::var)` + // here, maybe we'll find the reason XD + if (is_call(toks[ptr].type)) { auto call_node = new call_expr(toks[ptr].loc); call_node->set_first(node); while(is_call(toks[ptr].type)) { diff --git a/tools/repl.nas b/tools/repl.nas index 78768c1..12d388e 100644 --- a/tools/repl.nas +++ b/tools/repl.nas @@ -13,6 +13,7 @@ var content = []; var log_cache = ""; println("Nasal: This is experimental REPL"); +println("Tips : \";\" is automatically added at the end of the input line."); help(); var count_bracket = func(line) { From 6f259dc1ea2a43a99b4482812bc9b71d598aaaab Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 20 Aug 2023 22:35:24 +0800 Subject: [PATCH 05/15] :sparkles: fix old ambiguous syntax --- src/nasal_parse.cpp | 68 ++++++++++++++++++++++++++++----------------- src/nasal_parse.h | 5 ++-- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index e56e4e4..cd968e3 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -13,7 +13,7 @@ const error& parse::compile(const lexer& lexer) { match(tok::semi); } else if (need_semi_check(root->get_expressions().back()) && !lookahead(tok::eof)) { // the last expression can be recognized without semi - die(prevspan, "expected \";\""); + die(prevspan, "expected \";\" after this token"); } } update_location(root); @@ -60,6 +60,13 @@ void parse::die(const span& loc, std::string info) { err.err("parse", loc, info); } +void parse::next() { + if (lookahead(tok::eof)) { + return; + } + ++ptr; +} + void parse::match(tok type, const char* info) { if (!lookahead(type)) { if (info) { @@ -70,13 +77,10 @@ void parse::match(tok type, const char* info) { case tok::num:die(thisspan, "expected number"); break; case tok::str:die(thisspan, "expected string"); break; case tok::id: die(thisspan, "expected identifier");break; - default: die(thisspan, "expected '"+tokname.at(type)+"'"); break; + default: die(thisspan, "expected \""+tokname.at(type)+"\""); break; } return; } - if (lookahead(tok::eof)) { - return; - } next(); } @@ -91,7 +95,7 @@ bool parse::is_call(tok type) { bool parse::check_comma(const tok* panic_set) { for(u32 i=0;panic_set[i]!=tok::null;++i) { if (lookahead(panic_set[i])) { - die(prevspan, "expected ',' between scalars"); + die(prevspan, "expected \",\" between scalars"); return true; } } @@ -133,9 +137,21 @@ bool parse::check_func_end(expr* node) { return false; } +bool parse::check_in_curve_multi_definition() { + // we do not allow syntax like: + // func {}(var a, b, c) + // but we still allow syntax like: + // func {}(var a = 1) + // in fact, this syntax is not recommended + if (!lookahead(tok::lcurve) || toks[ptr+1].type!=tok::var) { + return false; + } + return toks[ptr+2].type==tok::id && toks[ptr+3].type==tok::comma; +} + bool parse::check_special_call() { // special call means like this: function_name(a:1,b:2,c:3); - u32 check_ptr=ptr, curve=1, bracket=0, brace=0; + u32 check_ptr = ptr, curve = 1, bracket = 0, brace = 0; while(toks[++check_ptr].type!=tok::eof && curve) { switch(toks[check_ptr].type) { case tok::lcurve: ++curve; break; @@ -236,7 +252,7 @@ vector_expr* parse::vec() { } } update_location(node); - match(tok::rbracket, "expected ']' when generating vector"); + match(tok::rbracket, "expected \"]\" when generating vector"); return node; } @@ -248,13 +264,13 @@ hash_expr* parse::hash() { if (lookahead(tok::comma)) { match(tok::comma); } else if (lookahead(tok::id) || lookahead(tok::str)) { // first set of hashmember - die(prevspan, "expected ',' between hash members"); + die(prevspan, "expected \",\" between hash members"); } else { break; } } update_location(node); - match(tok::rbrace, "expected '}' when generating hash"); + match(tok::rbrace, "expected \"}\" when generating hash"); return node; } @@ -309,13 +325,13 @@ void parse::params(function* func_node) { if (lookahead(tok::comma)) { match(tok::comma); } else if (lookahead(tok::id)) { // first set of identifier - die(prevspan, "expected ',' between identifiers"); + die(prevspan, "expected \",\" between identifiers"); } else { break; } } update_location(func_node); - match(tok::rcurve, "expected ')' after parameter list"); + match(tok::rcurve, "expected \")\" after parameter list"); return; } @@ -381,10 +397,10 @@ code_block* parse::expression_block() { match(tok::semi); } else if (need_semi_check(node->get_expressions().back()) && !lookahead(tok::rbrace)) { // the last expression can be recognized without semi - die(prevspan, "expected ';'"); + die(prevspan, "expected \";\" after this token"); } } - match(tok::rbrace, "expected '}' when generating expressions"); + match(tok::rbrace, "expected \"}\" when generating expressions"); } else { node->add_expression(expression()); if (lookahead(tok::semi)) { @@ -634,10 +650,12 @@ expr* parse::scalar() { die(thisspan, "expected scalar"); return null(); } - // check call and avoid ambiguous syntax - // i don't know why using `&& !(lookahead(tok::lcurve) && toks[ptr+1].type==tok::var)` - // here, maybe we'll find the reason XD - if (is_call(toks[ptr].type)) { + // check call and avoid ambiguous syntax: + // var f = func(){} + // (var a, b, c) = (1, 2, 3); + // will be incorrectly recognized like: + // var f = func(){}(var a, b, c) + if (is_call(toks[ptr].type) && !check_in_curve_multi_definition()) { auto call_node = new call_expr(toks[ptr].loc); call_node->set_first(node); while(is_call(toks[ptr].type)) { @@ -695,7 +713,7 @@ call_vector* parse::callv() { die(thisspan, "expected index value"); } update_location(node); - match(tok::rbracket, "expected ']' when calling vector"); + match(tok::rbracket, "expected \"]\" when calling vector"); return node; } @@ -722,7 +740,7 @@ call_function* parse::callf() { break; } update_location(node); - match(tok::rcurve, "expected ')' when calling function"); + match(tok::rcurve, "expected \")\" when calling function"); return node; } @@ -790,7 +808,7 @@ multi_identifier* parse::multi_id() { if (lookahead(tok::comma)) { match(tok::comma); } else if (lookahead(tok::id)) { // first set of identifier - die(prevspan, "expected ',' between identifiers"); + die(prevspan, "expected \",\" between identifiers"); } else { break; } @@ -820,7 +838,7 @@ tuple_expr* parse::multi_scalar() { } } update_location(node); - match(tok::rcurve, "expected ')' after multi-scalar"); + match(tok::rcurve, "expected \")\" after multi-scalar"); return node; } @@ -887,7 +905,7 @@ for_expr* parse::for_loop() { } else { node->set_initial(calc()); } - match(tok::semi, "expected ';' in for(;;)"); + match(tok::semi, "expected \";\" in for(;;)"); // conditional expression if (lookahead(tok::eof)) { @@ -898,7 +916,7 @@ for_expr* parse::for_loop() { } else { node->set_condition(calc()); } - match(tok::semi, "expected ';' in for(;;)"); + match(tok::semi, "expected \";\" in for(;;)"); //after loop expression if (lookahead(tok::eof)) { @@ -935,7 +953,7 @@ forei_expr* parse::forei_loop() { die(thisspan, "expected iterator"); } node->set_iterator(iter_gen()); - match(tok::semi, "expected ';' in foreach/forindex(iter;vector)"); + match(tok::semi, "expected \";\" in foreach/forindex(iter;vector)"); if (lookahead(tok::eof)) { die(thisspan, "expected vector"); } diff --git a/src/nasal_parse.h b/src/nasal_parse.h index c29e7bf..9ee59bb 100644 --- a/src/nasal_parse.h +++ b/src/nasal_parse.h @@ -77,13 +77,14 @@ private: private: void die(const span&,std::string); - void next() {++ptr;} - void match(tok type, const char* info=nullptr); + void next(); + void match(tok, const char* info=nullptr); bool lookahead(tok); bool is_call(tok); bool check_comma(const tok*); bool check_tuple(); bool check_func_end(expr*); + bool check_in_curve_multi_definition(); bool check_special_call(); bool need_semi_check(expr*); void update_location(expr*); From 00449c2bfb8ec5e4b9dfc70f39d99e5ca7fe9fd1 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Mon, 21 Aug 2023 21:35:34 +0800 Subject: [PATCH 06/15] :zap: optimize code --- src/nasal_lexer.cpp | 6 +++--- test/httptest.nas | 23 +++++++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/nasal_lexer.cpp b/src/nasal_lexer.cpp index facfe13..c745cef 100644 --- a/src/nasal_lexer.cpp +++ b/src/nasal_lexer.cpp @@ -11,11 +11,11 @@ bool lexer::skip(char c) { } bool lexer::is_id(char c) { - return (c=='_') || ('a'<=c && c<='z') || ('A'<=c && c<='Z') || (c<0); + return (c=='_') || std::isalpha(c) || (c<0); } bool lexer::is_hex(char c) { - return ('0'<=c && c<='9') || ('a'<=c && c<='f') || ('A'<=c && c<='F'); + return std::isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c<='F'); } bool lexer::is_oct(char c) { @@ -23,7 +23,7 @@ bool lexer::is_oct(char c) { } bool lexer::is_dec(char c) { - return '0'<=c && c<='9'; + return std::isdigit(c); } bool lexer::is_str(char c) { diff --git a/test/httptest.nas b/test/httptest.nas index 2fac7f8..be0f6bb 100644 --- a/test/httptest.nas +++ b/test/httptest.nas @@ -48,28 +48,31 @@ http.establish("127.0.0.1",8080); var highlight_style=" "; var html_read_file=func(filename){ From ba629e57d7dacb467dd3b0880b55c99d8e9a8304 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 23 Aug 2023 00:59:35 +0800 Subject: [PATCH 07/15] :zap: optimize lexer --- src/nasal_lexer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nasal_lexer.cpp b/src/nasal_lexer.cpp index c745cef..f7b6c84 100644 --- a/src/nasal_lexer.cpp +++ b/src/nasal_lexer.cpp @@ -15,7 +15,7 @@ bool lexer::is_id(char c) { } bool lexer::is_hex(char c) { - return std::isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c<='F'); + return std::isxdigit(c); } bool lexer::is_oct(char c) { @@ -127,7 +127,7 @@ token lexer::id_gen() { u32 begin_line = line; u32 begin_column = column; std::string str = ""; - while(ptr Date: Thu, 24 Aug 2023 23:24:04 +0800 Subject: [PATCH 08/15] :zap: optimize framework of vm --- src/main.cpp | 12 ++++++---- src/nasal_gc.cpp | 23 +++++++++++++------ src/nasal_gc.h | 35 +++++++++++++++++++--------- src/nasal_vm.cpp | 60 ++++++++++++++++++++++++------------------------ src/nasal_vm.h | 19 ++++++++++----- 5 files changed, 90 insertions(+), 59 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 29c8864..6867690 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -114,7 +114,6 @@ void execute( parse parse; linker ld; codegen gen; - vm ctx; // lexer scans file to get tokens lex.scan(file).chkerr(); @@ -150,15 +149,18 @@ void execute( // run auto start = clk::now(); if (cmd&VM_DEBUG) { - dbg().run(gen, ld, argv, cmd&VM_PROFILE, cmd&VM_PROF_ALL); + auto debugger = std::unique_ptr(new dbg); + debugger->run(gen, ld, argv, cmd&VM_PROFILE, cmd&VM_PROF_ALL); } else if (cmd&VM_TIME || cmd&VM_EXEC) { - ctx.run(gen, ld, argv, cmd&VM_DETAIL); + auto runtime = std::unique_ptr(new vm); + runtime->run(gen, ld, argv, cmd&VM_DETAIL); } // get running time + auto end = clk::now(); 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 "; + std::clog << (end-start).count()*1.0/den << "s.\n\n"; } } diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index ee6b1e2..31fa605 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -133,17 +133,20 @@ std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) { } void nas_co::clear() { - for(u32 i = 0; i& vec, usize begin, usize end) { } void gc::mark_context_root(std::vector& bfs_queue) { - + // scan global + for(usize i = 0; ivm_num) { + bfs_queue.push_back(val); + } + } // scan now running context, this context maybe related to coroutine or main for(var* i = rctx->stack; i<=rctx->top; ++i) { if (i->type>vm_num) { @@ -479,7 +488,7 @@ void gc::mark_upval(std::vector& bfs_queue, nas_upval& upval) { void gc::mark_co(std::vector& bfs_queue, nas_co& co) { bfs_queue.push_back(co.ctx.funcr); bfs_queue.push_back(co.ctx.upvalr); - for(var* i = co.stack; i<=co.ctx.top; ++i) { + for(var* i = co.ctx.stack; i<=co.ctx.top; ++i) { if (i->type>vm_num) { bfs_queue.push_back(*i); } diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 901db8e..51909ca 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -202,14 +202,14 @@ public: }; struct context { - u32 pc; - var* localr; - var* memr; - var funcr; - var upvalr; - var* canary; - var* stack; - var* top; + u32 pc = 0; + var* localr = nullptr; + var* memr = nullptr; + var funcr = var::nil(); + var upvalr = var::nil(); + var* canary = nullptr; + var* stack = nullptr; + var* top = nullptr; }; struct nas_co { @@ -219,11 +219,16 @@ struct nas_co { dead }; - var stack[STACK_DEPTH]; context ctx; status status; - nas_co() {clear();} + nas_co() { + ctx.stack = new var[STACK_DEPTH]; + clear(); + } + ~nas_co() { + delete[] ctx.stack; + } void clear(); }; @@ -281,6 +286,10 @@ struct gc { /* main context temporary storage */ context mctx; + /* global storage */ + var* main_context_global = nullptr; + usize main_context_global_size = 0; + /* runtime context */ context* rctx = nullptr; nas_co* cort = nullptr; // running coroutine @@ -315,7 +324,11 @@ struct gc { i64 max_mark_time = 0; i64 max_sweep_time = 0; - gc(context* _ctx): rctx(_ctx) {} + void set(context* _ctx, var* _global, usize _size) { + rctx = _ctx; + main_context_global = _global; + main_context_global_size = _size; + } private: /* gc functions */ diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 6249aec..0bb57c0 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -5,7 +5,7 @@ void vm::init( const std::vector& nums, const std::vector& natives, const std::vector& code, - const std::unordered_map& global, + const std::unordered_map& global_symbol, const std::vector& filenames, const std::vector& argv ) { @@ -23,28 +23,29 @@ void vm::init( 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; + ctx.canary = ctx.stack+STACK_DEPTH-1; // stack[STACK_DEPTH-1] + ctx.top = ctx.stack; - /* clear main stack */ + /* clear main stack and global */ for(u32 i = 0; istack==stack? stack+bytecode[0].num:ngc.rctx->stack; - var* ctx_top = ngc.rctx->stack==stack? ctx.top:ngc.rctx->top; + var* bottom = ctx.stack; + var* top = ctx.top; + std::stack ret; - for(var* i = bottom; i<=ctx_top; ++i) { + for(var* i = bottom; i<=top; ++i) { if (i->type==vm_ret && i->ret()!=0) { ret.push(i->ret()); } } ret.push(ctx.pc); // store the position program crashed + std::clog << "trace back (" - << (ngc.rctx->stack==stack? "main":"coroutine") + << (ngc.cort? "coroutine":"main") << ")\n"; codestream::set(cnum, cstr, native.data(), files); for(u32 p = 0, same = 0, prev = 0xffffffff; !ret.empty(); prev = p, ret.pop()) { @@ -121,19 +123,17 @@ void vm::traceback() { } void vm::stackinfo(const u32 limit = 10) { - /* bytecode[0].num is the global size */ - const u32 gsize = ngc.rctx->stack==stack? bytecode[0].num:0; - var* t = ctx.top; - var* bottom = ngc.rctx->stack+gsize; + var* top = ctx.top; + var* bottom = ctx.stack; std::clog << "stack (0x" << std::hex << (u64)bottom << std::dec; - std::clog << " <+" << gsize << ">, limit " << limit << ", total "; - std::clog << (t=bottom; ++i, --t) { + std::clog << ", limit " << limit << ", total "; + std::clog << (top=bottom; ++i, --top) { std::clog << " 0x" << std::hex << std::setw(6) << std::setfill('0') - << (u64)(t-ngc.rctx->stack) << std::dec + << (u64)(top-ngc.rctx->stack) << std::dec << " "; - valinfo(t[0]); + valinfo(top[0]); } } @@ -141,7 +141,7 @@ void vm::reginfo() { std::clog << "registers (" << (ngc.cort? "coroutine":"main") << ")\n" << std::hex << " [pc ] | pc | 0x" << ctx.pc << "\n" - << " [global] | addr | 0x" << (u64)stack << "\n" + << " [global] | addr | 0x" << (u64)global << "\n" << " [local ] | addr | 0x" << (u64)ctx.localr << "\n" << " [memr ] | addr | 0x" << (u64)ctx.memr << "\n" << " [canary] | addr | 0x" << (u64)ctx.canary << "\n" @@ -153,16 +153,16 @@ void vm::reginfo() { void vm::gstate() { // bytecode[0].op is op_intg - if (!bytecode[0].num || stack[0].type==vm_none) { + if (!bytecode[0].num || global[0].type==vm_none) { return; } std::clog << "global (0x" << std::hex - << (u64)stack << " <+0>)\n" << std::dec; + << (u64)global << ")\n" << std::dec; for(u32 i = 0; istack) + << " <+" << (u64)(ctx.localr-ctx.stack) << ">)\n" << std::dec; for(u32 i = 0; istack==stack) { + if (!ngc.cort) { // in main context, exit directly std::exit(1); } else { diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 3b54cf7..93d352a 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -29,7 +29,7 @@ protected: gc ngc; /* main stack */ - var stack[STACK_DEPTH]; + var* global = nullptr; /* values used for debugger */ const std::string* files = nullptr; // file name list @@ -46,7 +46,7 @@ protected: const std::vector&); /* debug functions */ - bool verbose; + bool verbose = false; void valinfo(var&); void traceback(); void stackinfo(const u32); @@ -151,7 +151,14 @@ protected: public: /* constructor of vm instance */ - vm(): ngc(&ctx), verbose(false) {} + vm() { + ctx.stack = new var[STACK_DEPTH]; + global = new var[STACK_DEPTH]; + } + ~vm() { + delete[] ctx.stack; + delete[] global; + } /* execution entry */ void run( @@ -184,7 +191,7 @@ inline void vm::o_intl() { } inline void vm::o_loadg() { - stack[imm[ctx.pc]] = (ctx.top--)[0]; + global[imm[ctx.pc]] = (ctx.top--)[0]; } inline void vm::o_loadl() { @@ -534,7 +541,7 @@ inline void vm::o_feach() { inline void vm::o_callg() { // get main stack directly - (++ctx.top)[0] = stack[imm[ctx.pc]]; + (++ctx.top)[0] = global[imm[ctx.pc]]; } inline void vm::o_calll() { @@ -819,7 +826,7 @@ inline void vm::o_slc2() { } inline void vm::o_mcallg() { - ctx.memr = stack+imm[ctx.pc]; + ctx.memr = global+imm[ctx.pc]; (++ctx.top)[0] = ctx.memr[0]; // push value in this memory space on stack // to avoid being garbage collected From ae5c76ecd5a4f1ff826c9cfaec0270c611b73b19 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 27 Aug 2023 00:25:49 +0800 Subject: [PATCH 09/15] :zap: maybe do not need o_intg anymore --- src/nasal_opcode.h | 2 +- src/nasal_vm.cpp | 12 ++++++------ src/nasal_vm.h | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/nasal_opcode.h b/src/nasal_opcode.h index d7f93fc..2a4e4d5 100644 --- a/src/nasal_opcode.h +++ b/src/nasal_opcode.h @@ -7,7 +7,7 @@ enum op_code_type:u8 { op_exit, // stop the virtual machine - op_intg, // global scope size, set stack top + op_intg, // init global scope op_intl, // local scope size op_loadg, // load global value op_loadl, // load local value diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 0bb57c0..caebcda 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -13,6 +13,7 @@ void vm::init( cstr = strs.data(); bytecode = code.data(); files = filenames.data(); + global_size = global_symbol.size(); /* set native functions */ native = natives; @@ -24,7 +25,7 @@ void vm::init( ctx.funcr = nil; ctx.upvalr = nil; ctx.canary = ctx.stack+STACK_DEPTH-1; // stack[STACK_DEPTH-1] - ctx.top = ctx.stack; + ctx.top = ctx.stack; // nothing is on stack /* clear main stack and global */ for(u32 i = 0; i=bottom; ++i, --top) { std::clog << " 0x" << std::hex << std::setw(6) << std::setfill('0') - << (u64)(top-ngc.rctx->stack) << std::dec + << (u64)(top-bottom) << std::dec << " "; valinfo(top[0]); } @@ -152,13 +153,12 @@ void vm::reginfo() { } void vm::gstate() { - // bytecode[0].op is op_intg - if (!bytecode[0].num || global[0].type==vm_none) { + if (!global_size || global[0].type==vm_none) { return; } std::clog << "global (0x" << std::hex << (u64)global << ")\n" << std::dec; - for(u32 i = 0; i Date: Sun, 27 Aug 2023 17:46:10 +0800 Subject: [PATCH 10/15] :sparkles: add experimental REPL (cpp) --- CMakeLists.txt | 3 +- makefile | 7 ++- src/main.cpp | 28 +++++---- src/nasal_codegen.cpp | 4 +- src/nasal_codegen.h | 2 +- src/repl.cpp | 137 ++++++++++++++++++++++++++++++++++++++++++ src/repl.h | 28 +++++++++ tools/repl.nas | 3 + 8 files changed, 195 insertions(+), 17 deletions(-) create mode 100644 src/repl.cpp create mode 100644 src/repl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a2a6f13..ef2d704 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,8 @@ set(NASAL_OBJECT_SOURCE_FILE ${CMAKE_SOURCE_DIR}/src/nasal_parse.cpp ${CMAKE_SOURCE_DIR}/src/nasal_vm.cpp ${CMAKE_SOURCE_DIR}/src/optimizer.cpp - ${CMAKE_SOURCE_DIR}/src/symbol_finder.cpp) + ${CMAKE_SOURCE_DIR}/src/symbol_finder.cpp + ${CMAKE_SOURCE_DIR}/src/repl.cpp) add_library(nasal-object STATIC ${NASAL_OBJECT_SOURCE_FILE}) target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src) diff --git a/makefile b/makefile index 456f98d..1f94936 100644 --- a/makefile +++ b/makefile @@ -23,7 +23,8 @@ NASAL_HEADER=\ src/math_lib.h\ src/dylib_lib.h\ src/unix_lib.h\ - src/coroutine.h + src/coroutine.h\ + src/repl.h NASAL_OBJECT=\ build/nasal_err.o\ @@ -49,6 +50,7 @@ NASAL_OBJECT=\ build/coroutine.o\ build/nasal_vm.o\ build/nasal_dbg.o\ + build/repl.o\ build/main.o # for test @@ -67,6 +69,9 @@ build/main.o: $(NASAL_HEADER) src/main.cpp | build 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/repl.o: src/nasal.h src/repl.h src/repl.cpp | build + $(CXX) -std=$(STD) -c -O3 src/repl.cpp -fno-exceptions -fPIC -o build/repl.o -I . + 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 . diff --git a/src/main.cpp b/src/main.cpp index 6867690..c1fb578 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,21 +11,22 @@ #include "nasal_codegen.h" #include "nasal_vm.h" #include "nasal_dbg.h" +#include "repl.h" #include #include #include -const u32 VM_RAW_AST = 1; -const u32 VM_AST = 1<<1; -const u32 VM_CODE = 1<<2; -const u32 VM_TIME = 1<<3; -const u32 VM_EXEC = 1<<4; -const u32 VM_DETAIL = 1<<5; -const u32 VM_DEBUG = 1<<6; -const u32 VM_SYMINFO = 1<<7; -const u32 VM_PROFILE = 1<<8; -const u32 VM_PROF_ALL = 1<<9; +const u32 VM_RAW_AST = 1; +const u32 VM_AST = 1<<1; +const u32 VM_CODE = 1<<2; +const u32 VM_TIME = 1<<3; +const u32 VM_EXEC = 1<<4; +const u32 VM_DETAIL = 1<<5; +const u32 VM_DEBUG = 1<<6; +const u32 VM_SYMINFO = 1<<7; +const u32 VM_PROFILE = 1<<8; +const u32 VM_PROF_ALL = 1<<9; std::ostream& help(std::ostream& out) { out @@ -53,6 +54,7 @@ std::ostream& help(std::ostream& out) { << " --prof | show profiling result, available under debug mode.\n" << " --prof-all | show profiling result of all files," << "available under debug mode.\n" + << " -r, --repl | use repl interpreter(experimental).\n" << "file:\n" << " | execute file.\n" << "argv:\n" @@ -129,9 +131,8 @@ void execute( ld.link(parse, file, cmd&VM_DETAIL).chkerr(); // optimizer does simple optimization on ast - auto opt = new optimizer; + auto opt = std::unique_ptr(new optimizer); opt->do_optimization(parse.tree()); - delete opt; if (cmd&VM_AST) { auto dumper = std::unique_ptr(new ast_dumper); dumper->dump(parse.tree()); @@ -178,6 +179,9 @@ i32 main(i32 argc, const char* argv[]) { std::clog << help; } else if (s=="-v" || s=="--version") { std::clog << version; + } else if (s=="-r" || s=="--repl") { + auto repl_module = std::unique_ptr(new repl::repl); + repl_module->execute(); } else if (s[0]!='-') { execute(s, {}, VM_EXEC); } else { diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 28477c8..9a9fc1a 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -1144,7 +1144,7 @@ void codegen::ret_gen(return_expr* node) { gen(op_ret, 0, node->get_location()); } -const error& codegen::compile(parse& parse, linker& import, bool repl) { +const error& codegen::compile(parse& parse, linker& import) { init_native_function(); init_file_map(import.get_file_list()); @@ -1157,7 +1157,7 @@ const error& codegen::compile(parse& parse, linker& import, bool repl) { // search global symbols first find_symbol(parse.tree()); - gen(op_intg, repl? STACK_DEPTH/2:global.size(), parse.tree()->get_location()); + gen(op_intg, global.size(), parse.tree()->get_location()); // generate main block block_gen(parse.tree()); diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 141f75b..121befc 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -132,7 +132,7 @@ public: public: codegen() = default; - const error& compile(parse&, linker&, bool repl = false); + const error& compile(parse&, linker&); void print(std::ostream&); void symbol_dump(std::ostream&) const; }; diff --git a/src/repl.cpp b/src/repl.cpp new file mode 100644 index 0000000..3be8f19 --- /dev/null +++ b/src/repl.cpp @@ -0,0 +1,137 @@ +#include "repl.h" +#include "nasal_lexer.h" +#include "nasal_parse.h" +#include "nasal_import.h" +#include "optimizer.h" +#include "nasal_codegen.h" +#include "nasal_vm.h" + +namespace repl { + +std::string repl::readline(std::string prompt = ">>> ") { + auto line = std::string(""); + std::cout << prompt; + std::getline(std::cin, line,'\n'); + return line; +} + +void repl::update_temp_file() { + auto content = std::string(""); + for(const auto& i : source) { + content += i + "\n"; + } + + std::ofstream out(".temp.nas", std::ios::binary); + out << content; +} + +bool repl::check_need_more_input() { + while(true) { + update_temp_file(); + auto nasal_lexer = std::unique_ptr(new lexer); + if (nasal_lexer->scan(".temp.nas").geterr()) { + return false; + } + + i64 in_curve = 0; + i64 in_bracket = 0; + i64 in_brace = 0; + for(const auto& t : nasal_lexer->result()) { + switch(t.type) { + case tok::lcurve: ++in_curve; break; + case tok::rcurve: --in_curve; break; + case tok::lbracket: ++in_bracket; break; + case tok::rbracket: --in_bracket; break; + case tok::lbrace: ++in_brace; break; + case tok::rbrace: --in_brace; break; + default: break; + } + } + if (!in_curve && !in_bracket && !in_brace) { + break; + } + auto line = readline("... "); + source.back() += "\n" + line; + } + return true; +} + +void repl::help() { + std::cout << ".h, .help | show help\n"; + std::cout << ".e, .exit | quit the REPL\n"; + std::cout << ".q, .quit | quit the REPL\n"; + std::cout << ".c, .clear | clear the screen\n"; + std::cout << "\n"; +} + +bool repl::run() { + update_temp_file(); + + auto nasal_lexer = std::unique_ptr(new lexer); + auto nasal_parser = std::unique_ptr(new parse); + auto nasal_linker = std::unique_ptr(new linker); + auto nasal_opt = std::unique_ptr(new optimizer); + auto nasal_codegen = std::unique_ptr(new codegen); + auto nasal_runtime = std::unique_ptr(new vm); + + if (nasal_lexer->scan(".temp.nas").geterr()) { + return false; + } + + if (nasal_parser->compile(*nasal_lexer).geterr()) { + return false; + } + + if (nasal_linker->link(*nasal_parser, ".temp.nas", true).geterr()) { + return false; + } + + nasal_opt->do_optimization(nasal_parser->tree()); + if (nasal_codegen->compile(*nasal_parser, *nasal_linker).geterr()) { + return false; + } + + nasal_runtime->run(*nasal_codegen, *nasal_linker, {}, false); + + return true; +} + +void repl::execute() { + source = {}; + std::cout << "Nasal REPL interpreter(experimental).\n"; + help(); + + while(true) { + auto line = readline(); + if (!line.length()) { + continue; + } + + if (line == ".e" || line == ".exit" || line == ".q" || line == ".quit") { + break; + } else if (line == ".h" || line == ".help") { + help(); + continue; + } else if (line == ".c" || line == ".clear") { + std::cout << "\033c"; + continue; + } else if (line[0] == "."[0]) { + std::cout << "no such command \"" << line; + std::cout << "\", input \".help\" for help\n"; + continue; + } + + source.push_back(line); + if (!check_need_more_input()) { + source.pop_back(); + continue; + } + + if (!run()) { + source.pop_back(); + } + std::cout << "\n"; + } +} + +} \ No newline at end of file diff --git a/src/repl.h b/src/repl.h new file mode 100644 index 0000000..3a2ef8a --- /dev/null +++ b/src/repl.h @@ -0,0 +1,28 @@ +#pragma once + +#include "nasal.h" + +#include +#include +#include +#include +#include + +namespace repl { + +class repl { +private: + std::vector source; + +private: + std::string readline(std::string); + bool check_need_more_input(); + void update_temp_file(); + void help(); + bool run(); + +public: + void execute(); +}; + +} \ No newline at end of file diff --git a/tools/repl.nas b/tools/repl.nas index 12d388e..74a3cc2 100644 --- a/tools/repl.nas +++ b/tools/repl.nas @@ -31,6 +31,9 @@ var count_bracket = func(line) { while(1) { var line = readline(">>> "); + if (!size(line)) { + continue; + } if (line == ".exit" or line == ".quit") { break; } elsif (line == ".help") { From a0e6047296c1f72cd38b108c24be5cf13df72812 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Thu, 31 Aug 2023 00:32:01 +0800 Subject: [PATCH 11/15] :sparkles: update test/datalog.nas --- src/main.cpp | 2 +- test/calc.nas | 2 +- test/datalog.nas | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c1fb578..f9cfe84 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,7 @@ std::ostream& help(std::ostream& out) { << "option:\n" << " -h, --help | get help.\n" << " -v, --version | get version.\n" + << " -r, --repl | use repl interpreter(experimental).\n" << "\nnasal [option] [argv]\n" << "option:\n" << " -a, --ast | view ast after link/optimize process.\n" @@ -54,7 +55,6 @@ std::ostream& help(std::ostream& out) { << " --prof | show profiling result, available under debug mode.\n" << " --prof-all | show profiling result of all files," << "available under debug mode.\n" - << " -r, --repl | use repl interpreter(experimental).\n" << "file:\n" << " | execute file.\n" << "argv:\n" diff --git a/test/calc.nas b/test/calc.nas index f1de5ac..440701e 100644 --- a/test/calc.nas +++ b/test/calc.nas @@ -49,7 +49,7 @@ var count=func(s,c){ } var column=func(number){ - number=number>=1000?substr(str(number/1000),0,3)~'k':str(number); + number=number>=1000?substr(str(number/1000),0,4)~'k':str(number); return padding.leftpad(number,6); } diff --git a/test/datalog.nas b/test/datalog.nas index 4530a24..6757856 100644 --- a/test/datalog.nas +++ b/test/datalog.nas @@ -159,4 +159,46 @@ for(var i=10;i<1e6;i*=10) { println("cartesian"); for(var i=100;i<600;i+=100) { cartesian(i); +} + +var person_data = []; +var person = func(name, age) { + append(person_data, [name, age]); + return person_data; +} + +var know_data = []; +var know = func(name_a, name_b) { + append(know_data, [name_a, name_b]); +} + +person("a", 1); +person("b", 2); +person("c", 3); +person("d", 4); + +know("a", "b"); +know("b", "c"); +know("c", "d"); +know("d", "a"); + +# maybe_know(a, b) :- know(a, tmp), know(tmp, b). +var maybe_know_data = []; + +var temp = []; + +foreach(var i; know_data) { + foreach(var j; know_data) { + append(temp, [i[0], i[1], j[0], j[1]]); + } +} + +foreach(var i; temp) { + if (!cmp(i[1], i[2])) { + append(maybe_know_data, [i, i[0], i[3]]); + } +} + +foreach(var res; maybe_know_data) { + println(res[0], " -> ", res[1], " ", res[2]); } \ No newline at end of file From ec03f0aee0ec49c91600b59f5c254e334e9b3a9f Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 6 Sep 2023 00:12:01 +0800 Subject: [PATCH 12/15] :zap: repl does not write temp file now --- module/nasocket.cpp | 2 +- src/nasal_err.cpp | 26 +++++++++++++++++++++++--- src/nasal_err.h | 12 ++++++++++++ src/nasal_lexer.cpp | 8 ++++++++ src/repl.cpp | 21 +++++++++++++++------ 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/module/nasocket.cpp b/module/nasocket.cpp index 71b95c8..7dba4c1 100644 --- a/module/nasocket.cpp +++ b/module/nasocket.cpp @@ -8,7 +8,7 @@ #include #pragma comment(lib,"ws2_32") -class WSAmanager{ +class WSAmanager { private: WSAData data; public: diff --git a/src/nasal_err.cpp b/src/nasal_err.cpp index d13471f..5075e71 100644 --- a/src/nasal_err.cpp +++ b/src/nasal_err.cpp @@ -1,4 +1,5 @@ #include "nasal_err.h" + #ifdef _WIN32 #include // use SetConsoleTextAttribute struct for_reset { @@ -6,7 +7,11 @@ struct for_reset { for_reset() { GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &scr); } -} reset_ter_color; + static for_reset* singleton() { + static for_reset windows_set; + return &windows_set; + } +}; #endif std::ostream& back_white(std::ostream& s) { @@ -57,7 +62,7 @@ std::ostream& white(std::ostream& s) { std::ostream& reset(std::ostream& s) { #ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), - reset_ter_color.scr.wAttributes); + for_reset::singleton()->scr.wAttributes); #else s << "\033[0m"; #endif @@ -68,7 +73,22 @@ void flstream::load(const std::string& f) { if (file==f) { // don't need to load a loaded file return; } else { - file=f; + file = f; + } + + if (repl_file_info::instance()->in_repl_mode && + repl_file_info::instance()->repl_file_name==file) { + const auto& source = repl_file_info::instance()->repl_file_source; + res = {}; + size_t pos = 0, last = 0; + while ((pos = source.find("\n", last))!=std::string::npos) { + res.push_back(source.substr(last, pos - last)); + last = pos + 1; + } + if (lastin_repl_mode && + repl_file_info::instance()->repl_file_name==file) { + err.load(file); + filename = file; + res = repl_file_info::instance()->repl_file_source; + return; + } + // check file exsits and it is a regular file struct stat buffer; if (stat(file.c_str(), &buffer)==0 && !S_ISREG(buffer.st_mode)) { diff --git a/src/repl.cpp b/src/repl.cpp index 3be8f19..ef8fea3 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -20,16 +20,14 @@ void repl::update_temp_file() { for(const auto& i : source) { content += i + "\n"; } - - std::ofstream out(".temp.nas", std::ios::binary); - out << content; + repl_file_info::instance()->repl_file_source = content; } bool repl::check_need_more_input() { while(true) { update_temp_file(); auto nasal_lexer = std::unique_ptr(new lexer); - if (nasal_lexer->scan(".temp.nas").geterr()) { + if (nasal_lexer->scan("").geterr()) { return false; } @@ -67,6 +65,10 @@ void repl::help() { bool repl::run() { update_temp_file(); + using clk = std::chrono::high_resolution_clock; + const auto den = clk::duration::period::den; + auto start = clk::now(); + auto nasal_lexer = std::unique_ptr(new lexer); auto nasal_parser = std::unique_ptr(new parse); auto nasal_linker = std::unique_ptr(new linker); @@ -74,7 +76,7 @@ bool repl::run() { auto nasal_codegen = std::unique_ptr(new codegen); auto nasal_runtime = std::unique_ptr(new vm); - if (nasal_lexer->scan(".temp.nas").geterr()) { + if (nasal_lexer->scan("").geterr()) { return false; } @@ -82,7 +84,7 @@ bool repl::run() { return false; } - if (nasal_linker->link(*nasal_parser, ".temp.nas", true).geterr()) { + if (nasal_linker->link(*nasal_parser, "", true).geterr()) { return false; } @@ -91,6 +93,8 @@ bool repl::run() { return false; } + auto end = clk::now(); + std::clog << "[compile time: " << (end-start).count()*1.0/den << "s]\n"; nasal_runtime->run(*nasal_codegen, *nasal_linker, {}, false); return true; @@ -98,6 +102,9 @@ bool repl::run() { void repl::execute() { source = {}; + auto repl_file_handle = repl_file_info::instance(); + repl_file_handle->in_repl_mode = true; + std::cout << "Nasal REPL interpreter(experimental).\n"; help(); @@ -127,9 +134,11 @@ void repl::execute() { continue; } + // run program if (!run()) { source.pop_back(); } + std::cout << "\n"; } } From 298b54c9ec5fffff7f2e88489c8d663e689803f3 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 6 Sep 2023 19:29:59 +0800 Subject: [PATCH 13/15] :bug: fix out of bound bug --- src/nasal_parse.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index cd968e3..e1aa64b 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -189,7 +189,10 @@ bool parse::need_semi_check(expr* node) { } void parse::update_location(expr* node) { - node->update_location(toks[ptr].loc); + if (!ptr) { + return; + } + node->update_location(toks[ptr-1].loc); } null_expr* parse::null() { From d89f290a8a08c66954c92e8bbb97fad46e5e4d4a Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Thu, 7 Sep 2023 23:14:17 +0800 Subject: [PATCH 14/15] :zap: fix out of bound bug & delete fatal in lexer --- makefile | 3 ++- src/nasal_err.cpp | 14 ++++++-------- src/nasal_err.h | 13 ------------- src/nasal_lexer.cpp | 21 +++++++++++++++------ src/nasal_lexer.h | 5 ++++- src/repl.cpp | 9 ++++----- src/repl.h | 12 ++++++++++++ 7 files changed, 43 insertions(+), 34 deletions(-) diff --git a/makefile b/makefile index 1f94936..5ec7f3e 100644 --- a/makefile +++ b/makefile @@ -72,7 +72,7 @@ build/nasal_misc.o: src/nasal.h src/nasal_misc.cpp | build build/repl.o: src/nasal.h src/repl.h src/repl.cpp | build $(CXX) -std=$(STD) -c -O3 src/repl.cpp -fno-exceptions -fPIC -o build/repl.o -I . -build/nasal_err.o: src/nasal.h src/nasal_err.h src/nasal_err.cpp | build +build/nasal_err.o: src/nasal.h src/repl.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.h src/nasal_gc.h src/nasal_gc.cpp | build @@ -88,6 +88,7 @@ build/nasal_import.o: \ build/nasal_lexer.o: \ src/nasal.h\ + src/repl.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 . diff --git a/src/nasal_err.cpp b/src/nasal_err.cpp index 5075e71..eca1714 100644 --- a/src/nasal_err.cpp +++ b/src/nasal_err.cpp @@ -1,4 +1,5 @@ #include "nasal_err.h" +#include "repl.h" #ifdef _WIN32 #include // use SetConsoleTextAttribute @@ -76,9 +77,9 @@ void flstream::load(const std::string& f) { file = f; } - if (repl_file_info::instance()->in_repl_mode && - repl_file_info::instance()->repl_file_name==file) { - const auto& source = repl_file_info::instance()->repl_file_source; + if (repl::info::instance()->in_repl_mode && + repl::info::instance()->repl_file_name==file) { + const auto& source = repl::info::instance()->repl_file_source; res = {}; size_t pos = 0, last = 0; while ((pos = source.find("\n", last))!=std::string::npos) { @@ -87,6 +88,8 @@ void flstream::load(const std::string& f) { } if (lastin_repl_mode && - repl_file_info::instance()->repl_file_name==file) { + if (repl::info::instance()->in_repl_mode && + repl::info::instance()->repl_file_name==file) { err.load(file); filename = file; - res = repl_file_info::instance()->repl_file_source; + res = repl::info::instance()->repl_file_source; return; } @@ -123,7 +124,7 @@ std::string lexer::utf8_gen() { err.err("lexer", {line, column-1, line, column, filename}, "invalid utf-8 <"+utf_info+">"); - err.fatal("lexer", "fatal error occurred, stop"); + ++invalid_char; } str += tmp; column += 2; // may have some problems because not all the unicode takes 2 space @@ -358,8 +359,16 @@ const error& lexer::scan(const std::string& file) { } else { err_char(); } + if (invalid_char>10) { + err.err("lexer", "too many invalid characters, stop"); + break; + } + } + if (toks.size()) { + toks.push_back({toks.back().loc, tok::eof, ""}); + } else { + toks.push_back({{line, column, line, column, filename}, tok::eof, ""}); } - toks.push_back({{line, column, line, column, filename}, tok::eof, ""}); res = ""; return err; } diff --git a/src/nasal_lexer.h b/src/nasal_lexer.h index b824ce9..5317a06 100644 --- a/src/nasal_lexer.h +++ b/src/nasal_lexer.h @@ -95,8 +95,11 @@ private: usize ptr; std::string filename; std::string res; + error err; + u64 invalid_char; std::vector toks; + const std::unordered_map typetbl { {"true" ,tok::tktrue }, {"false" ,tok::tkfalse }, @@ -175,7 +178,7 @@ private: token dots(); token calc_opr(); public: - lexer(): line(1), column(0), ptr(0), filename(""), res("") {} + lexer(): line(1), column(0), ptr(0), filename(""), res(""), invalid_char(0) {} const error& scan(const std::string&); const std::vector& result() const {return toks;} }; diff --git a/src/repl.cpp b/src/repl.cpp index ef8fea3..8982547 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -20,7 +20,7 @@ void repl::update_temp_file() { for(const auto& i : source) { content += i + "\n"; } - repl_file_info::instance()->repl_file_source = content; + info::instance()->repl_file_source = content; } bool repl::check_need_more_input() { @@ -45,7 +45,7 @@ bool repl::check_need_more_input() { default: break; } } - if (!in_curve && !in_bracket && !in_brace) { + if (in_curve<=0 && in_bracket<=0 && in_brace<=0) { break; } auto line = readline("... "); @@ -94,7 +94,7 @@ bool repl::run() { } auto end = clk::now(); - std::clog << "[compile time: " << (end-start).count()*1.0/den << "s]\n"; + std::clog << "[compile time: " << (end-start).count()*1000.0/den << " ms]\n"; nasal_runtime->run(*nasal_codegen, *nasal_linker, {}, false); return true; @@ -102,8 +102,7 @@ bool repl::run() { void repl::execute() { source = {}; - auto repl_file_handle = repl_file_info::instance(); - repl_file_handle->in_repl_mode = true; + info::instance()->in_repl_mode = true; std::cout << "Nasal REPL interpreter(experimental).\n"; help(); diff --git a/src/repl.h b/src/repl.h index 3a2ef8a..f1c9b9c 100644 --- a/src/repl.h +++ b/src/repl.h @@ -10,6 +10,18 @@ namespace repl { +struct info { + bool in_repl_mode = false; + std::string repl_file_name = ""; + std::string repl_file_source = ""; + + // singleton + static info* instance() { + static info info; + return &info; + } +}; + class repl { private: std::vector source; From cd4e0c171673b0c144a72e7524ff89d1c38065d9 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Fri, 8 Sep 2023 00:33:57 +0800 Subject: [PATCH 15/15] :art: add namespace --- src/ast_dumper.cpp | 6 +++++- src/ast_dumper.h | 6 +++++- src/ast_visitor.cpp | 6 +++++- src/ast_visitor.h | 6 +++++- src/main.cpp | 24 ++++++++++++------------ src/nasal_ast.cpp | 6 +++++- src/nasal_ast.h | 4 ++++ src/nasal_codegen.cpp | 4 ++++ src/nasal_codegen.h | 4 ++++ src/nasal_dbg.cpp | 4 ++++ src/nasal_dbg.h | 4 ++++ src/nasal_err.cpp | 6 +++++- src/nasal_err.h | 4 ++++ src/nasal_import.cpp | 4 ++++ src/nasal_import.h | 7 ++++++- src/nasal_lexer.cpp | 4 ++++ src/nasal_lexer.h | 4 ++++ src/nasal_parse.cpp | 4 ++++ src/nasal_parse.h | 6 +++++- src/nasal_vm.cpp | 4 ++++ src/nasal_vm.h | 6 +++++- src/optimizer.cpp | 6 +++++- src/optimizer.h | 4 ++++ src/repl.cpp | 4 +++- src/repl.h | 4 +++- src/symbol_finder.cpp | 6 +++++- src/symbol_finder.h | 6 +++++- 27 files changed, 127 insertions(+), 26 deletions(-) diff --git a/src/ast_dumper.cpp b/src/ast_dumper.cpp index 84f62f2..c46bfd0 100644 --- a/src/ast_dumper.cpp +++ b/src/ast_dumper.cpp @@ -2,6 +2,8 @@ #include +namespace nasal { + bool ast_dumper::visit_null_expr(null_expr* node) { dump_indent(); std::cout << "null" << format_location(node->get_location()); @@ -478,4 +480,6 @@ bool ast_dumper::visit_return_expr(return_expr* node) { pop_indent(); } return true; -} \ No newline at end of file +} + +} diff --git a/src/ast_dumper.h b/src/ast_dumper.h index 1f520d2..1385698 100644 --- a/src/ast_dumper.h +++ b/src/ast_dumper.h @@ -6,6 +6,8 @@ #include #include +namespace nasal { + class ast_dumper:public ast_visitor { private: std::vector indent; @@ -78,4 +80,6 @@ public: void dump(code_block* root) { root->accept(this); } -}; \ No newline at end of file +}; + +} diff --git a/src/ast_visitor.cpp b/src/ast_visitor.cpp index d9aa45a..677c043 100644 --- a/src/ast_visitor.cpp +++ b/src/ast_visitor.cpp @@ -1,5 +1,7 @@ #include "ast_visitor.h" +namespace nasal { + bool ast_visitor::visit_expr(expr* node) { node->accept(this); return true; @@ -231,4 +233,6 @@ bool ast_visitor::visit_return_expr(return_expr* node) { node->get_value()->accept(this); } return true; -} \ No newline at end of file +} + +} diff --git a/src/ast_visitor.h b/src/ast_visitor.h index 9586633..62f4dff 100644 --- a/src/ast_visitor.h +++ b/src/ast_visitor.h @@ -2,6 +2,8 @@ #include "nasal_ast.h" +namespace nasal { + class ast_visitor { public: virtual bool visit_expr(expr*); @@ -40,4 +42,6 @@ public: virtual bool visit_continue_expr(continue_expr*); virtual bool visit_break_expr(break_expr*); virtual bool visit_return_expr(return_expr*); -}; \ No newline at end of file +}; + +} diff --git a/src/main.cpp b/src/main.cpp index f9cfe84..6f6316e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,7 +89,7 @@ std::ostream& version(std::ostream& out) { num = (num+rand())*(1.0/(RAND_MAX+1.0)); } if (num<0.01) { - parse::easter_egg(); + nasal::parse::easter_egg(); } out << "nasal interpreter version " << __nasver; out << " (" << __DATE__ << " " << __TIME__ << ")\n"; @@ -112,10 +112,10 @@ void execute( using clk = std::chrono::high_resolution_clock; const auto den = clk::duration::period::den; - lexer lex; - parse parse; - linker ld; - codegen gen; + nasal::lexer lex; + nasal::parse parse; + nasal::linker ld; + nasal::codegen gen; // lexer scans file to get tokens lex.scan(file).chkerr(); @@ -123,7 +123,7 @@ void execute( // parser gets lexer's token list to compile parse.compile(lex).chkerr(); if (cmd&VM_RAW_AST) { - auto dumper = std::unique_ptr(new ast_dumper); + auto dumper = std::unique_ptr(new nasal::ast_dumper); dumper->dump(parse.tree()); } @@ -131,10 +131,10 @@ void execute( ld.link(parse, file, cmd&VM_DETAIL).chkerr(); // optimizer does simple optimization on ast - auto opt = std::unique_ptr(new optimizer); + auto opt = std::unique_ptr(new nasal::optimizer); opt->do_optimization(parse.tree()); if (cmd&VM_AST) { - auto dumper = std::unique_ptr(new ast_dumper); + auto dumper = std::unique_ptr(new nasal::ast_dumper); dumper->dump(parse.tree()); } @@ -150,10 +150,10 @@ void execute( // run auto start = clk::now(); if (cmd&VM_DEBUG) { - auto debugger = std::unique_ptr(new dbg); + auto debugger = std::unique_ptr(new nasal::dbg); debugger->run(gen, ld, argv, cmd&VM_PROFILE, cmd&VM_PROF_ALL); } else if (cmd&VM_TIME || cmd&VM_EXEC) { - auto runtime = std::unique_ptr(new vm); + auto runtime = std::unique_ptr(new nasal::vm); runtime->run(gen, ld, argv, cmd&VM_DETAIL); } @@ -180,8 +180,8 @@ i32 main(i32 argc, const char* argv[]) { } else if (s=="-v" || s=="--version") { std::clog << version; } else if (s=="-r" || s=="--repl") { - auto repl_module = std::unique_ptr(new repl::repl); - repl_module->execute(); + auto repl = std::unique_ptr(new nasal::repl::repl); + repl->execute(); } else if (s[0]!='-') { execute(s, {}, VM_EXEC); } else { diff --git a/src/nasal_ast.cpp b/src/nasal_ast.cpp index 5b2610c..a1c8859 100644 --- a/src/nasal_ast.cpp +++ b/src/nasal_ast.cpp @@ -1,6 +1,8 @@ #include "nasal_ast.h" #include "ast_visitor.h" +namespace nasal { + void expr::accept(ast_visitor* visitor) { visitor->visit_expr(this); } @@ -365,4 +367,6 @@ return_expr::~return_expr() { void return_expr::accept(ast_visitor* visitor) { visitor->visit_return_expr(this); -} \ No newline at end of file +} + +} diff --git a/src/nasal_ast.h b/src/nasal_ast.h index ffffd95..6e04e84 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -6,6 +6,8 @@ #include #include +namespace nasal { + enum class expr_type:u32 { ast_null = 0, // null node ast_block, // code block @@ -669,3 +671,5 @@ public: expr* get_value() {return value;} void accept(ast_visitor*) override; }; + +} diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 9a9fc1a..1b3c6d6 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -1,5 +1,7 @@ #include "nasal_codegen.h" +namespace nasal { + void codegen::init_file_map(const std::vector& file_list) { file_map = {}; for(usize i = 0; i #include +namespace nasal { + class debug_prof_data { private: static const usize operand_size = op_code_type::op_ret + 1; @@ -167,3 +169,5 @@ public: bool ); }; + +} diff --git a/src/nasal_err.cpp b/src/nasal_err.cpp index eca1714..c3ce95e 100644 --- a/src/nasal_err.cpp +++ b/src/nasal_err.cpp @@ -1,6 +1,8 @@ #include "nasal_err.h" #include "repl.h" +namespace nasal { + #ifdef _WIN32 #include // use SetConsoleTextAttribute struct for_reset { @@ -184,4 +186,6 @@ void error::err( } } std::cerr << "\n\n"; -} \ No newline at end of file +} + +} diff --git a/src/nasal_err.h b/src/nasal_err.h index 8c0e50e..bbeeb2a 100644 --- a/src/nasal_err.h +++ b/src/nasal_err.h @@ -8,6 +8,8 @@ #include "nasal.h" +namespace nasal { + struct span { u32 begin_line; u32 begin_column; @@ -65,3 +67,5 @@ public: } u32 geterr() const {return cnt;} }; + +} diff --git a/src/nasal_import.cpp b/src/nasal_import.cpp index 31b862b..f7390ae 100644 --- a/src/nasal_import.cpp +++ b/src/nasal_import.cpp @@ -1,6 +1,8 @@ #include "nasal_import.h" #include "symbol_finder.h" +namespace nasal { + linker::linker(): show_path(false), lib_loaded(false), this_file(""), lib_path("") { @@ -346,3 +348,5 @@ const error& linker::link( delete old_tree_root; return err; } + +} diff --git a/src/nasal_import.h b/src/nasal_import.h index e50161f..fc53fe9 100644 --- a/src/nasal_import.h +++ b/src/nasal_import.h @@ -20,7 +20,9 @@ #include -class linker{ +namespace nasal { + +class linker { private: bool show_path; bool lib_loaded; @@ -31,6 +33,7 @@ private: std::vector module_load_stack; std::vector envpath; +private: bool import_check(expr*); bool exist(const std::string&); u16 find(const std::string&); @@ -53,3 +56,5 @@ public: const auto& get_this_file() const {return this_file;} const auto& get_lib_path() const {return lib_path;} }; + +} diff --git a/src/nasal_lexer.cpp b/src/nasal_lexer.cpp index 6874475..9b63ab8 100644 --- a/src/nasal_lexer.cpp +++ b/src/nasal_lexer.cpp @@ -7,6 +7,8 @@ #include "nasal_lexer.h" #include "repl.h" +namespace nasal { + bool lexer::skip(char c) { return c==' ' || c=='\n' || c=='\t' || c=='\r' || c==0; } @@ -372,3 +374,5 @@ const error& lexer::scan(const std::string& file) { res = ""; return err; } + +} diff --git a/src/nasal_lexer.h b/src/nasal_lexer.h index 5317a06..2862a57 100644 --- a/src/nasal_lexer.h +++ b/src/nasal_lexer.h @@ -19,6 +19,8 @@ #define S_ISREG(m) (((m)&0xF000)==0x8000) #endif +namespace nasal { + enum class tok:u32 { null=0, // null token (default token type) num, // number literal @@ -182,3 +184,5 @@ public: const error& scan(const std::string&); const std::vector& result() const {return toks;} }; + +} diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index e1aa64b..82257e6 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -1,6 +1,8 @@ #include "nasal_ast.h" #include "nasal_parse.h" +namespace nasal { + const error& parse::compile(const lexer& lexer) { toks=lexer.result().data(); ptr=in_func=in_loop=0; @@ -1057,3 +1059,5 @@ return_expr* parse::return_expression() { update_location(node); return node; } + +} diff --git a/src/nasal_parse.h b/src/nasal_parse.h index 9ee59bb..2d9f6dd 100644 --- a/src/nasal_parse.h +++ b/src/nasal_parse.h @@ -7,6 +7,8 @@ #include "nasal_lexer.h" #include "nasal_err.h" +namespace nasal { + class parse { #define thisspan (toks[ptr].loc) @@ -155,4 +157,6 @@ public: } const error& compile(const lexer&); static void easter_egg(); -}; \ No newline at end of file +}; + +} diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index caebcda..4ac5050 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -1,5 +1,7 @@ #include "nasal_vm.h" +namespace nasal { + void vm::init( const std::vector& strs, const std::vector& nums, @@ -442,3 +444,5 @@ mcallh: exec_nodie(o_mcallh); // -0 ret: exec_nodie(o_ret ); // -2 #endif } + +} diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 26e10d4..af86bf6 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -13,6 +13,8 @@ #pragma warning (disable:4102) #endif +namespace nasal { + class vm { protected: @@ -954,4 +956,6 @@ inline void vm::o_ret() { if (!ctx.pc) { ngc.ctxreserve(); } -} \ No newline at end of file +} + +} diff --git a/src/optimizer.cpp b/src/optimizer.cpp index ed5a0fe..3b785f4 100644 --- a/src/optimizer.cpp +++ b/src/optimizer.cpp @@ -1,5 +1,7 @@ #include "optimizer.h" +namespace nasal { + void optimizer::const_string( binary_operator* node, string_literal* left_node, @@ -129,4 +131,6 @@ bool optimizer::visit_unary_operator(unary_operator* node) { void optimizer::do_optimization(code_block* root) { root->accept(this); -} \ No newline at end of file +} + +} diff --git a/src/optimizer.h b/src/optimizer.h index dc6ba7a..3c33453 100644 --- a/src/optimizer.h +++ b/src/optimizer.h @@ -5,6 +5,8 @@ #include "nasal_ast.h" #include "ast_visitor.h" +namespace nasal { + class optimizer:public ast_visitor { private: void const_string(binary_operator*, string_literal*, string_literal*); @@ -18,3 +20,5 @@ public: public: void do_optimization(code_block*); }; + +} diff --git a/src/repl.cpp b/src/repl.cpp index 8982547..a9f3ae1 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -6,6 +6,7 @@ #include "nasal_codegen.h" #include "nasal_vm.h" +namespace nasal { namespace repl { std::string repl::readline(std::string prompt = ">>> ") { @@ -142,4 +143,5 @@ void repl::execute() { } } -} \ No newline at end of file +} +} diff --git a/src/repl.h b/src/repl.h index f1c9b9c..ffa0d6e 100644 --- a/src/repl.h +++ b/src/repl.h @@ -8,6 +8,7 @@ #include #include +namespace nasal { namespace repl { struct info { @@ -37,4 +38,5 @@ public: void execute(); }; -} \ No newline at end of file +} +} diff --git a/src/symbol_finder.cpp b/src/symbol_finder.cpp index 7f34a55..c5105ae 100644 --- a/src/symbol_finder.cpp +++ b/src/symbol_finder.cpp @@ -1,5 +1,7 @@ #include "symbol_finder.h" +namespace nasal { + bool symbol_finder::visit_definition_expr(definition_expr* node) { if (node->get_variable_name()) { symbols.push_back({ @@ -40,4 +42,6 @@ const std::vector& symbol_finder::do_find(code_block symbols.clear(); root->accept(this); return symbols; -} \ No newline at end of file +} + +} diff --git a/src/symbol_finder.h b/src/symbol_finder.h index 545e94e..3114179 100644 --- a/src/symbol_finder.h +++ b/src/symbol_finder.h @@ -7,6 +7,8 @@ #include #include +namespace nasal { + class symbol_finder:public ast_visitor { public: struct symbol_info { @@ -22,4 +24,6 @@ public: bool visit_function(function*) override; bool visit_iter_expr(iter_expr*) override; const std::vector& do_find(code_block*); -}; \ No newline at end of file +}; + +}