add multi-line error report and span

This commit is contained in:
ValKmjolnir 2023-03-08 01:12:01 +08:00
parent abe2464a67
commit 1678567c5d
9 changed files with 862 additions and 783 deletions

View File

@ -29,25 +29,25 @@ __Contact us if having great ideas to share!__
## __Introduction__ ## __Introduction__
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language) [Nasal](http://wiki.flightgear.org/Nasal_scripting_language)
is an ECMAscript-like language that used in [FlightGear](https://www.flightgear.org/). is an ECMAscript-like language used in [FlightGear](https://www.flightgear.org/).
The designer is [Andy Ross](https://github.com/andyross). The designer is [Andy Ross](https://github.com/andyross).
This interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++14`) This interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++14`)
without reusing the code in [Andy Ross's nasal interpreter](https://github.com/andyross/nasal). without reusing the code in [Andy Ross's nasal interpreter](https://github.com/andyross/nasal).
But we really appreciate that Andy created this amazing programming language and his interpreter. But we really appreciate that Andy created this amazing programming language.
This project uses __MIT license__ (2021/5/4). This project uses __MIT license__ (2021/5/4).
__Why writing this nasal interpreter?__ ### __Why writing this nasal interpreter?__
In 2019 summer holiday,
2019 summer,
members in [FGPRC](https://www.fgprc.org/) told me that it is hard to debug with nasal-console in Flightgear, members in [FGPRC](https://www.fgprc.org/) told me that it is hard to debug with nasal-console in Flightgear,
especially when checking syntax errors. especially when checking syntax errors.
So i wrote a new interpreter to help them checking syntax error and even, runtime error. So i wrote a new interpreter to help checking syntax error and runtime error.
I wrote the lexer, parser and I wrote the lexer, parser and
bytecode virtual machine to help checking errors. bytecode virtual machine to help checking errors.
We found it much easier to check syntax and runtime We found it much easier to debug.
errors.
You could also use this language to write some You could also use this language to write some
interesting programs and run them without the lib of Flightgear. interesting programs and run them without the lib of Flightgear.

View File

@ -29,17 +29,18 @@ __如果有好的意见或建议欢迎联系我们!__
## __简介__ ## __简介__
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language) [Nasal](http://wiki.flightgear.org/Nasal_scripting_language)
是一个与ECMAscript标准语法设计相似的编程语言并且作为运行脚本被著名的开源飞行模拟器 [FlightGear](https://www.flightgear.org/) 所依赖 是一款语法与ECMAscript相似的编程语言并作为运行脚本被著名开源飞行模拟器 [FlightGear](https://www.flightgear.org/) 所使用
该语言的设计者为 [Andy Ross](https://github.com/andyross)。 该语言的设计者为 [Andy Ross](https://github.com/andyross)。
该解释器项目由 [ValKmjolnir](https://github.com/ValKmjolnir) 完全使用 `C++`(`-std=c++14`)重新实现,没有复用 [Andy Ross的nasal解释器](https://github.com/andyross/nasal) 中的任何一行代码。尽管没有参考任何代码我们依然非常感谢Andy为我们带来了这样一个神奇且容易上手的编程语言。 该解释器项目由 [ValKmjolnir](https://github.com/ValKmjolnir) 完全使用 `C++`(`-std=c++14`)重新实现,没有复用 [Andy Ross的nasal解释器](https://github.com/andyross/nasal) 中的任何一行代码。尽管没有参考任何代码我们依然非常感谢Andy为我们带来了这样一个神奇且简洁的编程语言。
该项目已使用 __MIT__ 协议开源 (2021/5/4)。 该项目已使用 __MIT__ 协议开源 (2021/5/4)。
__我们为什么想要重新写一个nasal解释器?__ ### __我们为什么想要重新写一个nasal解释器?__
2019年暑假[FGPRC](https://www.fgprc.org.cn/) 的成员告诉我在Flightgear中提供的nasal控制台窗口中进行调试很不方便仅仅是想检查语法错误也得花时间打开软件等待加载进去后进行调试。所以我就写了一个全新的解释器来帮助他们检查语法错误甚至是检查运行时的错误。
我编写了nasal的词法分析器和语法分析器以及一个全新的字节码虚拟机并用这个运行时来进行nasal程序的调试。我们发现使用这个解释器来检测语法和运行时错误提高了我们的工作效率。 2019年暑假[FGPRC](https://www.fgprc.org.cn/) 的成员告诉我在Flightgear中提供的nasal控制台窗口中进行调试很不方便仅仅是想检查语法错误也得花时间打开软件等待加载进去后进行调试。所以我就写了一个全新的解释器来帮助他们检查语法错误以及运行时错误。
我编写了nasal的词法分析器和语法分析器以及一个全新的字节码虚拟机并用这个运行时来进行nasal程序的调试。我们发现使用这个解释器来检测语法和运行时错误极大的提高了效率。
你也可以使用这个语言来写一些与Flightgear运行环境无关的有趣的程序并用这个解释器来执行。你也可以让解释器来调用你自己编写的模块使它成为项目中一个非常有用的工具。 你也可以使用这个语言来写一些与Flightgear运行环境无关的有趣的程序并用这个解释器来执行。你也可以让解释器来调用你自己编写的模块使它成为项目中一个非常有用的工具。

View File

@ -115,10 +115,13 @@ void execute(const string& file,const std::vector<string>& argv,const u32 cmd) {
} }
i32 main(i32 argc,const char* argv[]) { i32 main(i32 argc,const char* argv[]) {
// output version info
if (argc<=1) { if (argc<=1) {
std::clog<<logo; std::clog<<logo;
return 0; return 0;
} }
// run directly or show help
if (argc==2) { if (argc==2) {
string s(argv[1]); string s(argv[1]);
if (s=="-h" || s=="--help") { if (s=="-h" || s=="--help") {
@ -130,6 +133,8 @@ i32 main(i32 argc,const char* argv[]) {
} }
return 0; return 0;
} }
// execute with arguments
std::unordered_map<string,u32> cmdlst={ std::unordered_map<string,u32> cmdlst={
{"--ast",VM_AST},{"-a",VM_AST}, {"--ast",VM_AST},{"-a",VM_AST},
{"--code",VM_CODE},{"-c",VM_CODE}, {"--code",VM_CODE},{"-c",VM_CODE},

View File

@ -4,6 +4,7 @@
#include <cstring> #include <cstring>
#include "nasal.h" #include "nasal.h"
#include "nasal_err.h"
enum ast_node:u32 { enum ast_node:u32 {
ast_null=0, // null node ast_null=0, // null node
@ -145,16 +146,15 @@ const char* ast_name[]={
class ast { class ast {
private: private:
u32 nd_line; span loc;
u32 nd_col;
u32 nd_type; u32 nd_type;
f64 nd_num; f64 nd_num;
string nd_file;
string nd_str; string nd_str;
std::vector<ast> nd_child; std::vector<ast> nd_child;
public: public:
ast(const u32 l,const u32 c,const u32 t,const std::string& f) ast(const span& s,const u32 t)
: nd_line(l),nd_col(c),nd_type(t),nd_num(0),nd_file(f),nd_str("") {} : loc(s),nd_type(t),nd_num(0),nd_str("") {}
ast(const ast&) = default; ast(const ast&) = default;
ast(ast&&) = default; ast(ast&&) = default;
ast& operator=(const ast&) = default; ast& operator=(const ast&) = default;
@ -170,22 +170,35 @@ public:
void add(ast&& node) {nd_child.push_back(std::move(node));} void add(ast&& node) {nd_child.push_back(std::move(node));}
void add(const ast& node) {nd_child.push_back(node);} void add(const ast& node) {nd_child.push_back(node);}
void set_line(const u32 l) {nd_line=l;} void set_begin(const u32,const u32);
void set_end(const u32,const u32);
void set_type(const u32 t) {nd_type=t;} void set_type(const u32 t) {nd_type=t;}
void set_str(const string& s) {nd_str=s;} void set_str(const string& s) {nd_str=s;}
void set_num(const f64 n) {nd_num=n;} void set_num(const f64 n) {nd_num=n;}
u32 line() const {return nd_line;} u32 line() const {return loc.end_line;}
u32 col() const {return nd_col;} u32 col() const {return loc.end_column;}
u32 type() const {return nd_type;} u32 type() const {return nd_type;}
f64 num() const {return nd_num;} f64 num() const {return nd_num;}
const string& str() const {return nd_str;} const string& str() const {return nd_str;}
const string& file() const {return loc.file;}
const span& location() const {return loc;}
const std::vector<ast>& child() const {return nd_child;} const std::vector<ast>& child() const {return nd_child;}
std::vector<ast>& child() {return nd_child;} std::vector<ast>& child() {return nd_child;}
}; };
void ast::set_begin(const u32 l,const u32 c) {
loc.begin_line=l;
loc.begin_column=c;
}
void ast::set_end(const u32 l,const u32 c) {
loc.end_line=l;
loc.end_column=c;
}
void ast::clear() { void ast::clear() {
nd_line=nd_col=0; loc={0,0,0,0};
nd_num=0; nd_num=0;
nd_str.clear(); nd_str.clear();
nd_type=ast_null; nd_type=ast_null;
@ -198,10 +211,15 @@ void ast::dump() const{
} }
void ast::print(u32 depth,bool last,std::vector<string>& indent) const{ void ast::print(u32 depth,bool last,std::vector<string>& indent) const{
// output the indentation first
for(auto& i:indent) { for(auto& i:indent) {
std::cout<<i; std::cout<<i;
} }
// output ast node name
std::cout<<ast_name[nd_type]; std::cout<<ast_name[nd_type];
// output string literal and number
if (nd_type==ast_str || if (nd_type==ast_str ||
nd_type==ast_id || nd_type==ast_id ||
nd_type==ast_bool || nd_type==ast_bool ||
@ -212,7 +230,11 @@ void ast::print(u32 depth,bool last,std::vector<string>& indent) const{
} else if (nd_type==ast_num || nd_type==ast_file) { } else if (nd_type==ast_num || nd_type==ast_file) {
std::cout<<":"<<nd_num; std::cout<<":"<<nd_num;
} }
std::cout<<" --> "<<nd_file<<":"<<nd_line<<":"<<nd_col<<"\n";
// okay, we must know that begin_column starts from index 0
std::cout<<" --> "<<loc.file<<":"<<loc.begin_line<<":"<<loc.begin_column+1<<"\n";
// output tree structure
if (last && depth) { if (last && depth) {
indent.back()=" "; indent.back()=" ";
} else if (!last && depth) { } else if (!last && depth) {

View File

@ -295,7 +295,7 @@ bool codegen::check_memory_reachable(const ast& node) {
void codegen::die(const string& info,const u32 line,const u32 col,const u32 len=1) { void codegen::die(const string& info,const u32 line,const u32 col,const u32 len=1) {
err.load(file[fileindex]); err.load(file[fileindex]);
err.err("code",line,col,len,info); err.err("code",{line,col-len,line,col,file[fileindex]},info);
} }
void codegen::regist_num(const f64 num) { void codegen::regist_num(const f64 num) {

View File

@ -1,160 +1,223 @@
#pragma once #pragma once
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> // MSVC need this to use std::getline #include <sstream> // MSVC need this to use std::getline
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include "nasal.h" #include "nasal.h"
#ifdef _WIN32 struct span {
#include <windows.h> // use SetConsoleTextAttribute u32 begin_line;
struct for_reset { u32 begin_column;
CONSOLE_SCREEN_BUFFER_INFO scr; u32 end_line;
for_reset() { u32 end_column;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&scr); string file;
} };
} reset_ter_color;
#endif #ifdef _WIN32
#include <windows.h> // use SetConsoleTextAttribute
std::ostream& back_white(std::ostream& s) { struct for_reset {
#ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO scr;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xf0); for_reset() {
#else GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&scr);
s<<"\033[7m"; }
#endif } reset_ter_color;
return s; #endif
}
std::ostream& back_white(std::ostream& s) {
std::ostream& red(std::ostream& s) { #ifdef _WIN32
#ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xf0);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c); #else
#else s<<"\033[7m";
s<<"\033[91;1m"; #endif
#endif return s;
return s; }
}
std::ostream& red(std::ostream& s) {
std::ostream& cyan(std::ostream& s) { #ifdef _WIN32
#ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03); #else
#else s<<"\033[91;1m";
s<<"\033[36;1m"; #endif
#endif return s;
return s; }
}
std::ostream& cyan(std::ostream& s) {
std::ostream& orange(std::ostream& s) { #ifdef _WIN32
#ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0e); #else
#else s<<"\033[36;1m";
s<<"\033[93;1m"; #endif
#endif return s;
return s; }
}
std::ostream& orange(std::ostream& s) {
std::ostream& white(std::ostream& s) { #ifdef _WIN32
#ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0e);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0f); #else
#else s<<"\033[93;1m";
s<<"\033[0m\033[1m"; #endif
#endif return s;
return s; }
}
std::ostream& white(std::ostream& s) {
std::ostream& reset(std::ostream& s) { #ifdef _WIN32
#ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0f);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),reset_ter_color.scr.wAttributes); #else
#else s<<"\033[0m\033[1m";
s<<"\033[0m"; #endif
#endif return s;
return s; }
}
std::ostream& reset(std::ostream& s) {
class flstream { #ifdef _WIN32
protected: SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),reset_ter_color.scr.wAttributes);
string file; #else
std::vector<string> res; s<<"\033[0m";
public: #endif
flstream():file("") {} return s;
void load(const string& f) { }
if (file==f) { // don't need to load a loaded file
return; class flstream {
} else { protected:
file=f; string file;
} std::vector<string> res;
public:
res.clear(); flstream():file("") {}
std::ifstream in(f,std::ios::binary); void load(const string&);
if (in.fail()) { const string& operator[](usize n) const {return res[n];}
std::cerr<<red<<"src: "<<reset<<"cannot open <"<<f<<">\n"; const string& name() const {return file;}
std::exit(1); usize size() const {return res.size();}
} };
while(!in.eof()) { class error:public flstream {
string line; private:
std::getline(in,line); u32 cnt; // counter for errors
res.push_back(line);
} string identation(usize len) {
} return string(len,' ');
const string& operator[](usize n) const {return res[n];} }
const string& name() const {return file;} string leftpad(u32 num,usize len) {
usize size() const {return res.size();} string res=std::to_string(num);
}; while(res.length()<len) {
res=" "+res;
class error:public flstream { }
private: return res;
u32 cnt; }
string identation(usize len) { public:
string tmp=""; error():cnt(0) {}
tmp.resize(len,' '); void fatal(const string&,const string&);
return tmp; void err(const string&,const string&);
} void err(const string&,const span&,const string&);
public:
error():cnt(0) {} void chkerr() const {
void fatal(const string& stage,const string& info) { if (cnt) {
std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n"; std::exit(1);
if (file.length()) { }
std::cerr<<cyan<<" --> "<<red<<file<<"\n\n"; }
} else { };
std::cerr<<"\n";
}
std::exit(1); void flstream::load(const string& f) {
} if (file==f) { // don't need to load a loaded file
void err(const string& stage,const string& info) { return;
++cnt; } else {
std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n"; file=f;
if (file.length()) { }
std::cerr<<cyan<<" --> "<<red<<file<<"\n\n";
} else { res.clear();
std::cerr<<"\n"; std::ifstream in(f,std::ios::binary);
} if (in.fail()) {
} std::cerr<<red<<"src: "<<reset<<"cannot open <"<<f<<">\n";
void err(const string& stage,u32 line,u32 col,u32 len,const string& info) { std::exit(1);
++cnt; }
col=col?col:1;
len=len?len:1; while(!in.eof()) {
string line;
std::cerr std::getline(in,line);
<<red<<stage<<": "<<white<<info<<reset<<"\n" res.push_back(line);
<<cyan<<" --> "<<red<<file<<":"<<line<<":"<<col<<reset<<"\n"; }
}
const string& code=line?res[line-1]:"# empty line";
const string iden=identation(std::to_string(line).length()); void error::fatal(const string& stage,const string& info) {
std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
std::cerr if (file.length()) {
<<cyan<<line<<" | "<<reset<<code<<"\n" std::cerr<<cyan<<" --> "<<red<<file<<"\n\n";
<<cyan<<iden<<" | "<<reset; } else {
for(i32 i=0;i<(i32)col-(i32)len;++i) std::cerr<<"\n";
std::cerr<<char(" \t"[code[i]=='\t']); }
for(u32 i=0;i<len;++i) std::exit(1);
std::cerr<<red<<"^"; }
std::cerr<<red<<" "<<info<<reset<<"\n\n";
} void error::err(const string& stage,const string& info) {
void chkerr() const { ++cnt;
if (cnt) { std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
std::exit(1); if (file.length()) {
} std::cerr<<cyan<<" --> "<<red<<file<<"\n\n";
} } else {
}; std::cerr<<"\n";
}
}
void error::err(const string& stage,const span& loc,const string& info) {
// load error occurred file into string lines
load(loc.file);
++cnt;
std::cerr
<<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 string iden=identation(maxlen);
for(u32 line=loc.begin_line;line<=loc.end_line;++line) {
if (!line || !res[line-1].length()) {
continue;
}
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";
}
continue;
}
const string& code=res[line-1];
std::cerr<<cyan<<leftpad(line,maxlen)<<" | "<<reset<<code<<"\n";
// output underline
std::cerr<<cyan<<iden<<" | "<<reset;
if (loc.begin_line==loc.end_line) {
for(i32 i=0;i<loc.begin_column;++i) {
std::cerr<<char(" \t"[code[i]=='\t']);
}
for(i32 i=loc.begin_column;i<loc.end_column;++i) {
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^")<<reset;
}
} else if (line==loc.begin_line) {
for(i32 i=0;i<loc.begin_column;++i) {
std::cerr<<char(" \t"[code[i]=='\t']);
}
for(i32 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(i32 i=0;i<code.size();++i) {
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^");
}
} else {
for(i32 i=0;i<loc.end_column;++i) {
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^");
}
}
if (line==loc.end_line) {
std::cerr<<reset;
} else {
std::cerr<<reset<<"\n";
}
}
std::cerr<<"\n\n";
}

View File

@ -159,7 +159,7 @@ ast linker::fimpt(ast& node) {
// avoid infinite loading loop // avoid infinite loading loop
filename=findf(filename); filename=findf(filename);
if (!filename.length() || exist(filename)) { if (!filename.length() || exist(filename)) {
return {0,0,ast_root,filename}; return {{0,0,0,0,filename},ast_root};
} }
// start importing... // start importing...
@ -176,12 +176,12 @@ ast linker::libimpt() {
parse par(err); parse par(err);
string filename=findf("lib.nas"); string filename=findf("lib.nas");
if (!filename.length()) { if (!filename.length()) {
return {0,0,ast_root,filename}; return {{0,0,0,0,filename},ast_root};
} }
// avoid infinite loading loop // avoid infinite loading loop
if (exist(filename)) { if (exist(filename)) {
return {0,0,ast_root,filename}; return {{0,0,0,0,filename},ast_root};
} }
// start importing... // start importing...
@ -194,7 +194,7 @@ ast linker::libimpt() {
} }
ast linker::load(ast& root,u16 fileindex) { ast linker::load(ast& root,u16 fileindex) {
ast tree(0,0,ast_root,files[fileindex]); ast tree({0,0,0,0,files[fileindex]},ast_root);
if (!lib_loaded) { if (!lib_loaded) {
link(tree,libimpt()); link(tree,libimpt());
lib_loaded=true; lib_loaded=true;
@ -207,7 +207,7 @@ ast linker::load(ast& root,u16 fileindex) {
} }
} }
// add root to the back of tree // add root to the back of tree
ast file_head(0,0,ast_file,files[fileindex]); ast file_head({0,0,0,0,files[fileindex]},ast_file);
file_head.set_num(fileindex); file_head.set_num(fileindex);
tree.add(std::move(file_head)); tree.add(std::move(file_head));
link(tree,std::move(root)); link(tree,std::move(root));

File diff suppressed because it is too large Load Diff

View File

@ -43,9 +43,8 @@
*/ */
class parse { class parse {
#define thisline (toks[ptr].tk_end_line) #define thisspan (toks[ptr].loc)
#define thiscol (toks[ptr].tk_end_column) #define prevspan (ptr!=0? toks[ptr-1].loc:toks[ptr].loc)
#define thislen (toks[ptr].str.length())
private: private:
u32 ptr; u32 ptr;
u32 in_func; // count function block u32 in_func; // count function block
@ -107,7 +106,7 @@ private:
{tok::geq ,">=" } {tok::geq ,">=" }
}; };
void die(u32,u32,u32,string,bool); void die(const span&,string);
void next() {++ptr;}; void next() {++ptr;};
void match(tok type,const char* info=nullptr); void match(tok type,const char* info=nullptr);
bool lookahead(tok); bool lookahead(tok);
@ -165,7 +164,8 @@ private:
public: public:
parse(error& e): parse(error& e):
ptr(0),in_func(0),in_loop(0), ptr(0),in_func(0),in_loop(0),
toks(nullptr),root(0,0,ast_root,""), toks(nullptr),
root({0,0,0,0,""},ast_root),
err(e) {} err(e) {}
const error& compile(const lexer&); const error& compile(const lexer&);
ast& tree() {return root;} ast& tree() {return root;}
@ -176,46 +176,34 @@ const error& parse::compile(const lexer& lexer) {
toks=lexer.result().data(); toks=lexer.result().data();
ptr=in_func=in_loop=0; ptr=in_func=in_loop=0;
root={0,0,ast_root,toks[0].file}; root={{0,0,0,0,toks[0].loc.file},ast_root};
while(!lookahead(tok::eof)) { while(!lookahead(tok::eof)) {
root.add(expr()); root.add(expr());
if (lookahead(tok::semi)) { if (lookahead(tok::semi)) {
match(tok::semi); match(tok::semi);
} else if (need_semi_check(root.child().back()) && !lookahead(tok::eof)) { } else if (need_semi_check(root.child().back()) && !lookahead(tok::eof)) {
// the last expression can be recognized without semi // the last expression can be recognized without semi
die(thisline,thiscol,thislen,"expected \";\"",true); die(prevspan,"expected \";\"");
} }
} }
return err; return err;
} }
void parse::die(u32 line,u32 col,u32 len,string info,bool prev=false) { void parse::die(const span& loc,string info) {
// tok::str's str has no \" err.err("parse",loc,info);
if (lookahead(tok::str)) {
col-=2;
len+=2;
}
// used to report lack of ',' ';'
if (prev && ptr) {
line=toks[ptr-1].tk_end_line;
col=toks[ptr-1].tk_end_column;
len=toks[ptr-1].str.length();
len+=toks[ptr-1].type==tok::str?2:0;
}
err.err("parse",line,col,lookahead(tok::eof)?1:len,info);
} }
void parse::match(tok type,const char* info) { void parse::match(tok type,const char* info) {
if (!lookahead(type)) { if (!lookahead(type)) {
if (info) { if (info) {
die(thisline,thiscol,thislen,info); die(thisspan,info);
return; return;
} }
switch(type) { switch(type) {
case tok::num:die(thisline,thiscol,thislen,"expected number"); break; case tok::num:die(thisspan,"expected number"); break;
case tok::str:die(thisline,thiscol,thislen,"expected string"); break; case tok::str:die(thisspan,"expected string"); break;
case tok::id: die(thisline,thiscol,thislen,"expected identifier");break; case tok::id: die(thisspan,"expected identifier");break;
default: die(thisline,thiscol,thislen,"expected '"+tokname[type]+"'"); break; default: die(thisspan,"expected '"+tokname[type]+"'"); break;
} }
return; return;
} }
@ -236,7 +224,7 @@ bool parse::is_call(tok type) {
bool parse::check_comma(const tok* panic_set) { bool parse::check_comma(const tok* panic_set) {
for(u32 i=0;panic_set[i]!=tok::null;++i) { for(u32 i=0;panic_set[i]!=tok::null;++i) {
if (lookahead(panic_set[i])) { if (lookahead(panic_set[i])) {
die(thisline,thiscol,thislen,"expected ',' between scalars",true); die(prevspan,"expected ',' between scalars");
return true; return true;
} }
} }
@ -319,36 +307,36 @@ bool parse::need_semi_check(const ast& node) {
} }
ast parse::null() { ast parse::null() {
return {toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file}; return {toks[ptr].loc,ast_null};
} }
ast parse::nil() { ast parse::nil() {
return {toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_nil,toks[ptr].file}; return {toks[ptr].loc,ast_nil};
} }
ast parse::num() { ast parse::num() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_num,toks[ptr].file); ast node(toks[ptr].loc,ast_num);
node.set_num(str2num(toks[ptr].str.c_str())); node.set_num(str2num(toks[ptr].str.c_str()));
match(tok::num); match(tok::num);
return node; return node;
} }
ast parse::str() { ast parse::str() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_str,toks[ptr].file); ast node(toks[ptr].loc,ast_str);
node.set_str(toks[ptr].str); node.set_str(toks[ptr].str);
match(tok::str); match(tok::str);
return node; return node;
} }
ast parse::id() { ast parse::id() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_id,toks[ptr].file); ast node(toks[ptr].loc,ast_id);
node.set_str(toks[ptr].str); node.set_str(toks[ptr].str);
match(tok::id); match(tok::id);
return node; return node;
} }
ast parse::bools() { ast parse::bools() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_bool,toks[ptr].file); ast node(toks[ptr].loc,ast_bool);
node.set_str(toks[ptr].str); node.set_str(toks[ptr].str);
if (lookahead(tok::tktrue)) { if (lookahead(tok::tktrue)) {
match(tok::tktrue); match(tok::tktrue);
@ -368,7 +356,7 @@ ast parse::vec() {
tok::func,tok::var,tok::lcurve,tok::floater, tok::func,tok::var,tok::lcurve,tok::floater,
tok::lbrace,tok::lbracket,tok::null tok::lbrace,tok::lbracket,tok::null
}; };
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_vec,toks[ptr].file); ast node(toks[ptr].loc,ast_vec);
match(tok::lbracket); match(tok::lbracket);
while(!lookahead(tok::rbracket)) { while(!lookahead(tok::rbracket)) {
node.add(calc()); node.add(calc());
@ -385,14 +373,14 @@ ast parse::vec() {
} }
ast parse::hash() { ast parse::hash() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_hash,toks[ptr].file); ast node(toks[ptr].loc,ast_hash);
match(tok::lbrace); match(tok::lbrace);
while(!lookahead(tok::rbrace)) { while(!lookahead(tok::rbrace)) {
node.add(pair()); node.add(pair());
if (lookahead(tok::comma)) { if (lookahead(tok::comma)) {
match(tok::comma); match(tok::comma);
} else if (lookahead(tok::id) || lookahead(tok::str)) { // first set of hashmember } else if (lookahead(tok::id) || lookahead(tok::str)) { // first set of hashmember
die(thisline,thiscol,thislen,"expected ',' between hash members",true); die(prevspan,"expected ',' between hash members");
} else { } else {
break; break;
} }
@ -402,7 +390,7 @@ ast parse::hash() {
} }
ast parse::pair() { ast parse::pair() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_pair,toks[ptr].file); ast node(toks[ptr].loc,ast_pair);
if (lookahead(tok::id)) { if (lookahead(tok::id)) {
node.add(id()); node.add(id());
} else if (lookahead(tok::str)) { } else if (lookahead(tok::str)) {
@ -417,7 +405,7 @@ ast parse::pair() {
ast parse::func() { ast parse::func() {
++in_func; ++in_func;
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_func,toks[ptr].file); ast node(toks[ptr].loc,ast_func);
match(tok::func); match(tok::func);
if (lookahead(tok::lcurve)) { if (lookahead(tok::lcurve)) {
node.add(params()); node.add(params());
@ -430,12 +418,12 @@ ast parse::func() {
} }
ast parse::params() { ast parse::params() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_params,toks[ptr].file); ast node(toks[ptr].loc,ast_params);
match(tok::lcurve); match(tok::lcurve);
while(!lookahead(tok::rcurve)) { while(!lookahead(tok::rcurve)) {
ast tmp=id(); ast tmp=id();
if (lookahead(tok::eq) || lookahead(tok::ellipsis)) { if (lookahead(tok::eq) || lookahead(tok::ellipsis)) {
ast special_arg(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file); ast special_arg(toks[ptr].loc,ast_null);
if (lookahead(tok::eq)) { if (lookahead(tok::eq)) {
match(tok::eq); match(tok::eq);
special_arg=std::move(tmp); special_arg=std::move(tmp);
@ -453,7 +441,7 @@ ast parse::params() {
if (lookahead(tok::comma)) { if (lookahead(tok::comma)) {
match(tok::comma); match(tok::comma);
} else if (lookahead(tok::id)) { // first set of identifier } else if (lookahead(tok::id)) { // first set of identifier
die(thisline,thiscol,thislen,"expected ',' between identifiers",true); die(prevspan,"expected ',' between identifiers");
} else { } else {
break; break;
} }
@ -471,10 +459,10 @@ ast parse::lcurve_expr() {
ast parse::expr() { ast parse::expr() {
tok type=toks[ptr].type; tok type=toks[ptr].type;
if ((type==tok::brk || type==tok::cont) && !in_loop) { if ((type==tok::brk || type==tok::cont) && !in_loop) {
die(thisline,thiscol,thislen,"must use break/continue in loops"); die(thisspan,"must use break/continue in loops");
} }
if (type==tok::ret && !in_func) { if (type==tok::ret && !in_func) {
die(thisline,thiscol,thislen,"must use return in functions"); die(thisspan,"must use return in functions");
} }
switch(type) { switch(type) {
case tok::tknil: case tok::tknil:
@ -501,19 +489,19 @@ ast parse::expr() {
case tok::ret: return ret_expr(); break; case tok::ret: return ret_expr(); break;
case tok::semi: break; case tok::semi: break;
default: default:
die(thisline,thiscol,thislen,"incorrect token <"+toks[ptr].str+">"); die(thisspan,"incorrect token <"+toks[ptr].str+">");
next(); next();
break; break;
} }
return {toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file}; return {toks[ptr].loc,ast_null};
} }
ast parse::exprs() { ast parse::exprs() {
if (lookahead(tok::eof)) { if (lookahead(tok::eof)) {
die(thisline,thiscol,thislen,"expected expression block"); die(thisspan,"expected expression block");
return null(); return null();
} }
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_block,toks[ptr].file); ast node(toks[ptr].loc,ast_block);
if (lookahead(tok::lbrace)) { if (lookahead(tok::lbrace)) {
match(tok::lbrace); match(tok::lbrace);
while(!lookahead(tok::rbrace) && !lookahead(tok::eof)) { while(!lookahead(tok::rbrace) && !lookahead(tok::eof)) {
@ -522,7 +510,7 @@ ast parse::exprs() {
match(tok::semi); match(tok::semi);
} else if (need_semi_check(node.child().back()) && !lookahead(tok::rbrace)) { } else if (need_semi_check(node.child().back()) && !lookahead(tok::rbrace)) {
// the last expression can be recognized without semi // the last expression can be recognized without semi
die(thisline,thiscol,thislen,"expected ';'",true); die(prevspan,"expected ';'");
} }
} }
match(tok::rbrace,"expected '}' when generating expressions"); match(tok::rbrace,"expected '}' when generating expressions");
@ -538,7 +526,7 @@ ast parse::calc() {
ast node=bitwise_or(); ast node=bitwise_or();
if (lookahead(tok::quesmark)) { if (lookahead(tok::quesmark)) {
// trinocular calculation // trinocular calculation
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_trino,toks[ptr].file); ast tmp(toks[ptr].loc,ast_trino);
match(tok::quesmark); match(tok::quesmark);
tmp.add(std::move(node)); tmp.add(std::move(node));
tmp.add(calc()); tmp.add(calc());
@ -547,13 +535,13 @@ ast parse::calc() {
node=std::move(tmp); node=std::move(tmp);
} else if (tok::eq<=toks[ptr].type && toks[ptr].type<=tok::lnkeq) { } else if (tok::eq<=toks[ptr].type && toks[ptr].type<=tok::lnkeq) {
// tok::eq~tok::lnkeq is 37 to 42,ast_equal~ast_lnkeq is 21~26 // tok::eq~tok::lnkeq is 37 to 42,ast_equal~ast_lnkeq is 21~26
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,(u32)toks[ptr].type-(u32)tok::eq+ast_equal,toks[ptr].file); ast tmp(toks[ptr].loc,(u32)toks[ptr].type-(u32)tok::eq+ast_equal);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(toks[ptr].type); match(toks[ptr].type);
tmp.add(calc()); tmp.add(calc());
node=std::move(tmp); node=std::move(tmp);
} else if (toks[ptr].type==tok::btandeq || toks[ptr].type==tok::btoreq || toks[ptr].type==tok::btxoreq) { } else if (toks[ptr].type==tok::btandeq || toks[ptr].type==tok::btoreq || toks[ptr].type==tok::btxoreq) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,(u32)toks[ptr].type-(u32)tok::btandeq+ast_btandeq,toks[ptr].file); ast tmp(toks[ptr].loc,(u32)toks[ptr].type-(u32)tok::btandeq+ast_btandeq);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(toks[ptr].type); match(toks[ptr].type);
tmp.add(calc()); tmp.add(calc());
@ -565,7 +553,7 @@ ast parse::calc() {
ast parse::bitwise_or() { ast parse::bitwise_or() {
ast node=bitwise_xor(); ast node=bitwise_xor();
while(lookahead(tok::btor)) { while(lookahead(tok::btor)) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_bitor,toks[ptr].file); ast tmp(toks[ptr].loc,ast_bitor);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tok::btor); match(tok::btor);
tmp.add(bitwise_xor()); tmp.add(bitwise_xor());
@ -577,7 +565,7 @@ ast parse::bitwise_or() {
ast parse::bitwise_xor() { ast parse::bitwise_xor() {
ast node=bitwise_and(); ast node=bitwise_and();
while(lookahead(tok::btxor)) { while(lookahead(tok::btxor)) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_bitxor,toks[ptr].file); ast tmp(toks[ptr].loc,ast_bitxor);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tok::btxor); match(tok::btxor);
tmp.add(bitwise_and()); tmp.add(bitwise_and());
@ -589,7 +577,7 @@ ast parse::bitwise_xor() {
ast parse::bitwise_and() { ast parse::bitwise_and() {
ast node=or_expr(); ast node=or_expr();
while(lookahead(tok::btand)) { while(lookahead(tok::btand)) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_bitand,toks[ptr].file); ast tmp(toks[ptr].loc,ast_bitand);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tok::btand); match(tok::btand);
tmp.add(or_expr()); tmp.add(or_expr());
@ -601,7 +589,7 @@ ast parse::bitwise_and() {
ast parse::or_expr() { ast parse::or_expr() {
ast node=and_expr(); ast node=and_expr();
while(lookahead(tok::opor)) { while(lookahead(tok::opor)) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_or,toks[ptr].file); ast tmp(toks[ptr].loc,ast_or);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tok::opor); match(tok::opor);
tmp.add(and_expr()); tmp.add(and_expr());
@ -613,7 +601,7 @@ ast parse::or_expr() {
ast parse::and_expr() { ast parse::and_expr() {
ast node=cmp_expr(); ast node=cmp_expr();
while(lookahead(tok::opand)) { while(lookahead(tok::opand)) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_and,toks[ptr].file); ast tmp(toks[ptr].loc,ast_and);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tok::opand); match(tok::opand);
tmp.add(cmp_expr()); tmp.add(cmp_expr());
@ -626,7 +614,7 @@ ast parse::cmp_expr() {
ast node=additive_expr(); ast node=additive_expr();
while(tok::cmpeq<=toks[ptr].type && toks[ptr].type<=tok::geq) { while(tok::cmpeq<=toks[ptr].type && toks[ptr].type<=tok::geq) {
// tok::cmpeq~tok::geq is 43~48,ast_cmpeq~ast_geq is 27~32 // tok::cmpeq~tok::geq is 43~48,ast_cmpeq~ast_geq is 27~32
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,(u32)toks[ptr].type-(u32)tok::cmpeq+ast_cmpeq,toks[ptr].file); ast tmp(toks[ptr].loc,(u32)toks[ptr].type-(u32)tok::cmpeq+ast_cmpeq);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(toks[ptr].type); match(toks[ptr].type);
tmp.add(additive_expr()); tmp.add(additive_expr());
@ -638,7 +626,7 @@ ast parse::cmp_expr() {
ast parse::additive_expr() { ast parse::additive_expr() {
ast node=multive_expr(); ast node=multive_expr();
while(lookahead(tok::add) || lookahead(tok::sub) || lookahead(tok::floater)) { while(lookahead(tok::add) || lookahead(tok::sub) || lookahead(tok::floater)) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file); ast tmp(toks[ptr].loc,ast_null);
switch(toks[ptr].type) { switch(toks[ptr].type) {
case tok::add: tmp.set_type(ast_add); break; case tok::add: tmp.set_type(ast_add); break;
case tok::sub: tmp.set_type(ast_sub); break; case tok::sub: tmp.set_type(ast_sub); break;
@ -656,7 +644,7 @@ ast parse::additive_expr() {
ast parse::multive_expr() { ast parse::multive_expr() {
ast node=(lookahead(tok::sub) || lookahead(tok::opnot) || lookahead(tok::floater))?unary():scalar(); ast node=(lookahead(tok::sub) || lookahead(tok::opnot) || lookahead(tok::floater))?unary():scalar();
while(lookahead(tok::mult) || lookahead(tok::div)) { while(lookahead(tok::mult) || lookahead(tok::div)) {
ast tmp(toks[ptr].tk_end_line,toks[ptr].tk_end_column,(u32)toks[ptr].type-(u32)tok::mult+ast_mult,toks[ptr].file); ast tmp(toks[ptr].loc,(u32)toks[ptr].type-(u32)tok::mult+ast_mult);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(toks[ptr].type); match(toks[ptr].type);
tmp.add((lookahead(tok::sub) || lookahead(tok::opnot) || lookahead(tok::floater))?unary():scalar()); tmp.add((lookahead(tok::sub) || lookahead(tok::opnot) || lookahead(tok::floater))?unary():scalar());
@ -666,7 +654,7 @@ ast parse::multive_expr() {
} }
ast parse::unary() { ast parse::unary() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file); ast node(toks[ptr].loc,ast_null);
switch(toks[ptr].type) { switch(toks[ptr].type) {
case tok::sub: node.set_type(ast_neg);match(tok::sub);break; case tok::sub: node.set_type(ast_neg);match(tok::sub);break;
case tok::opnot: node.set_type(ast_lnot);match(tok::opnot);break; case tok::opnot: node.set_type(ast_lnot);match(tok::opnot);break;
@ -678,7 +666,7 @@ ast parse::unary() {
} }
ast parse::scalar() { ast parse::scalar() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file); ast node(toks[ptr].loc,ast_null);
if (lookahead(tok::tknil)) { if (lookahead(tok::tknil)) {
node=nil(); node=nil();
match(tok::tknil); match(tok::tknil);
@ -707,13 +695,13 @@ ast parse::scalar() {
match(tok::eq); match(tok::eq);
node.add(calc()); node.add(calc());
} else { } else {
die(thisline,thiscol,thislen,"expected scalar"); die(thisspan,"expected scalar");
return node; return node;
} }
// check call and avoid ambiguous syntax // check call and avoid ambiguous syntax
if (is_call(toks[ptr].type) && !(lookahead(tok::lcurve) && toks[ptr+1].type==tok::var)) { if (is_call(toks[ptr].type) && !(lookahead(tok::lcurve) && toks[ptr+1].type==tok::var)) {
ast tmp=std::move(node); ast tmp=std::move(node);
node={toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_call,toks[ptr].file}; node={toks[ptr].loc,ast_call};
node.add(std::move(tmp)); node.add(std::move(tmp));
while(is_call(toks[ptr].type)) { while(is_call(toks[ptr].type)) {
node.add(call_scalar()); node.add(call_scalar());
@ -730,11 +718,11 @@ ast parse::call_scalar() {
default: break; default: break;
} }
// should never run this expression // should never run this expression
return {toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_nil,toks[ptr].file}; return {toks[ptr].loc,ast_nil};
} }
ast parse::callh() { ast parse::callh() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_callh,toks[ptr].file); ast node(toks[ptr].loc,ast_callh);
match(tok::dot); match(tok::dot);
node.set_str(toks[ptr].str); node.set_str(toks[ptr].str);
match(tok::id,"expected hashmap key"); // get key match(tok::id,"expected hashmap key"); // get key
@ -751,7 +739,7 @@ ast parse::callv() {
tok::func,tok::var,tok::lcurve,tok::floater, tok::func,tok::var,tok::lcurve,tok::floater,
tok::lbrace,tok::lbracket,tok::colon,tok::null tok::lbrace,tok::lbracket,tok::colon,tok::null
}; };
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_callv,toks[ptr].file); ast node(toks[ptr].loc,ast_callv);
match(tok::lbracket); match(tok::lbracket);
while(!lookahead(tok::rbracket)) { while(!lookahead(tok::rbracket)) {
node.add(subvec()); node.add(subvec());
@ -764,7 +752,7 @@ ast parse::callv() {
} }
} }
if (node.size()==0) { if (node.size()==0) {
die(node.line(),node.col(),1,"expected index value"); die(node.location(),"expected index value");
} }
match(tok::rbracket,"expected ']' when calling vector"); match(tok::rbracket,"expected ']' when calling vector");
return node; return node;
@ -780,7 +768,7 @@ ast parse::callf() {
tok::func,tok::var,tok::lcurve,tok::floater, tok::func,tok::var,tok::lcurve,tok::floater,
tok::lbrace,tok::lbracket,tok::null tok::lbrace,tok::lbracket,tok::null
}; };
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_callf,toks[ptr].file); ast node(toks[ptr].loc,ast_callf);
bool special_call=check_special_call(); bool special_call=check_special_call();
match(tok::lcurve); match(tok::lcurve);
while(!lookahead(tok::rcurve)) { while(!lookahead(tok::rcurve)) {
@ -799,7 +787,7 @@ ast parse::callf() {
ast parse::subvec() { ast parse::subvec() {
ast node=lookahead(tok::colon)?nil():calc(); ast node=lookahead(tok::colon)?nil():calc();
if (lookahead(tok::colon)) { if (lookahead(tok::colon)) {
ast tmp(node.line(),node.col(),ast_subvec,toks[ptr].file); ast tmp(toks[ptr].loc,ast_subvec);
match(tok::colon); match(tok::colon);
tmp.add(std::move(node)); tmp.add(std::move(node));
tmp.add((lookahead(tok::comma) || lookahead(tok::rbracket))?nil():calc()); tmp.add((lookahead(tok::comma) || lookahead(tok::rbracket))?nil():calc());
@ -809,13 +797,13 @@ ast parse::subvec() {
} }
ast parse::definition() { ast parse::definition() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_def,toks[ptr].file); ast node(toks[ptr].loc,ast_def);
if (lookahead(tok::var)) { if (lookahead(tok::var)) {
match(tok::var); match(tok::var);
switch(toks[ptr].type) { switch(toks[ptr].type) {
case tok::id: node.add(id());break; case tok::id: node.add(id());break;
case tok::lcurve: node.add(outcurve_def());break; case tok::lcurve: node.add(outcurve_def());break;
default: die(thisline,thiscol,thislen,"expected identifier");break; default: die(thisspan,"expected identifier");break;
} }
} else if (lookahead(tok::lcurve)) { } else if (lookahead(tok::lcurve)) {
node.add(incurve_def()); node.add(incurve_def());
@ -845,17 +833,17 @@ ast parse::outcurve_def() {
} }
ast parse::multi_id() { ast parse::multi_id() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_multi_id,toks[ptr].file); ast node(toks[ptr].loc,ast_multi_id);
while(!lookahead(tok::eof)) { while(!lookahead(tok::eof)) {
node.add(id()); node.add(id());
if (is_call(toks[ptr].type)) { if (is_call(toks[ptr].type)) {
ast tmp=call_scalar();// recognize calls but this is still a syntax error ast tmp=call_scalar();// recognize calls but this is still a syntax error
die(tmp.line(),tmp.col(),1,"cannot call identifier in multi-definition"); die(tmp.location(),"cannot call identifier in multi-definition");
} }
if (lookahead(tok::comma)) { if (lookahead(tok::comma)) {
match(tok::comma); match(tok::comma);
} else if (lookahead(tok::id)) { // first set of identifier } else if (lookahead(tok::id)) { // first set of identifier
die(thisline,thiscol,thislen,"expected ',' between identifiers",true); die(prevspan,"expected ',' between identifiers");
} else { } else {
break; break;
} }
@ -871,7 +859,7 @@ ast parse::multi_scalar() {
tok::func,tok::var,tok::lcurve,tok::floater, tok::func,tok::var,tok::lcurve,tok::floater,
tok::lbrace,tok::lbracket,tok::null tok::lbrace,tok::lbracket,tok::null
}; };
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_tuple,toks[ptr].file); ast node(toks[ptr].loc,ast_tuple);
match(tok::lcurve); match(tok::lcurve);
while(!lookahead(tok::rcurve)) { while(!lookahead(tok::rcurve)) {
node.add(calc()); node.add(calc());
@ -888,11 +876,11 @@ ast parse::multi_scalar() {
} }
ast parse::multi_assgin() { ast parse::multi_assgin() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_multi_assign,toks[ptr].file); ast node(toks[ptr].loc,ast_multi_assign);
node.add(multi_scalar()); node.add(multi_scalar());
match(tok::eq); match(tok::eq);
if (lookahead(tok::eof)) { if (lookahead(tok::eof)) {
die(thisline,thiscol,thislen,"expected value list"); die(thisspan,"expected value list");
return node; return node;
} }
if (lookahead(tok::lcurve)) { if (lookahead(tok::lcurve)) {
@ -905,7 +893,7 @@ ast parse::multi_assgin() {
ast parse::loop() { ast parse::loop() {
++in_loop; ++in_loop;
ast node(0,0,ast_null,toks[ptr].file); ast node(toks[ptr].loc,ast_null);
switch(toks[ptr].type) { switch(toks[ptr].type) {
case tok::rwhile: node=while_loop(); break; case tok::rwhile: node=while_loop(); break;
case tok::rfor: node=for_loop(); break; case tok::rfor: node=for_loop(); break;
@ -918,7 +906,7 @@ ast parse::loop() {
} }
ast parse::while_loop() { ast parse::while_loop() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_while,toks[ptr].file); ast node(toks[ptr].loc,ast_while);
match(tok::rwhile); match(tok::rwhile);
match(tok::lcurve); match(tok::lcurve);
node.add(calc()); node.add(calc());
@ -928,12 +916,12 @@ ast parse::while_loop() {
} }
ast parse::for_loop() { ast parse::for_loop() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_for,toks[ptr].file); ast node(toks[ptr].loc,ast_for);
match(tok::rfor); match(tok::rfor);
match(tok::lcurve); match(tok::lcurve);
// first expression // first expression
if (lookahead(tok::eof)) { if (lookahead(tok::eof)) {
die(thisline,thiscol,thislen,"expected definition"); die(thisspan,"expected definition");
} }
if (lookahead(tok::semi)) { if (lookahead(tok::semi)) {
node.add(null()); node.add(null());
@ -947,7 +935,7 @@ ast parse::for_loop() {
match(tok::semi,"expected ';' in for(;;)"); match(tok::semi,"expected ';' in for(;;)");
// conditional expression // conditional expression
if (lookahead(tok::eof)) { if (lookahead(tok::eof)) {
die(thisline,thiscol,thislen,"expected conditional expr"); die(thisspan,"expected conditional expr");
} }
if (lookahead(tok::semi)) { if (lookahead(tok::semi)) {
node.add(null()); node.add(null());
@ -957,7 +945,7 @@ ast parse::for_loop() {
match(tok::semi,"expected ';' in for(;;)"); match(tok::semi,"expected ';' in for(;;)");
//after loop expression //after loop expression
if (lookahead(tok::eof)) { if (lookahead(tok::eof)) {
die(thisline,thiscol,thislen,"expected calculation"); die(thisspan,"expected calculation");
} }
if (lookahead(tok::rcurve)) { if (lookahead(tok::rcurve)) {
node.add(null()); node.add(null());
@ -970,7 +958,7 @@ ast parse::for_loop() {
} }
ast parse::forei_loop() { ast parse::forei_loop() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file); ast node(toks[ptr].loc,ast_null);
switch(toks[ptr].type) { switch(toks[ptr].type) {
case tok::forindex:node.set_type(ast_forindex);match(tok::forindex);break; case tok::forindex:node.set_type(ast_forindex);match(tok::forindex);break;
case tok::foreach: node.set_type(ast_foreach); match(tok::foreach); break; case tok::foreach: node.set_type(ast_foreach); match(tok::foreach); break;
@ -980,12 +968,12 @@ ast parse::forei_loop() {
// first expression // first expression
// foreach/forindex must have an iterator to loop through // foreach/forindex must have an iterator to loop through
if (!lookahead(tok::var) && !lookahead(tok::id)) { if (!lookahead(tok::var) && !lookahead(tok::id)) {
die(thisline,thiscol,thislen,"expected iterator"); die(thisspan,"expected iterator");
} }
node.add(iter_gen()); node.add(iter_gen());
match(tok::semi,"expected ';' in foreach/forindex(iter;vector)"); match(tok::semi,"expected ';' in foreach/forindex(iter;vector)");
if (lookahead(tok::eof)) { if (lookahead(tok::eof)) {
die(thisline,thiscol,thislen,"expected vector"); die(thisspan,"expected vector");
} }
node.add(calc()); node.add(calc());
match(tok::rcurve); match(tok::rcurve);
@ -994,7 +982,7 @@ ast parse::forei_loop() {
} }
ast parse::iter_gen() { ast parse::iter_gen() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_null,toks[ptr].file); ast node(toks[ptr].loc,ast_null);
if (lookahead(tok::var)) { if (lookahead(tok::var)) {
match(tok::var); match(tok::var);
node.set_type(ast_iter); node.set_type(ast_iter);
@ -1010,8 +998,8 @@ ast parse::iter_gen() {
} }
ast parse::cond() { ast parse::cond() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_cond,toks[ptr].file); ast node(toks[ptr].loc,ast_cond);
ast ifnode(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_if,toks[ptr].file); ast ifnode(toks[ptr].loc,ast_if);
match(tok::rif); match(tok::rif);
match(tok::lcurve); match(tok::lcurve);
ifnode.add(calc()); ifnode.add(calc());
@ -1019,7 +1007,7 @@ ast parse::cond() {
ifnode.add(exprs()); ifnode.add(exprs());
node.add(std::move(ifnode)); node.add(std::move(ifnode));
while(lookahead(tok::elsif)) { while(lookahead(tok::elsif)) {
ast elsifnode(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_elsif,toks[ptr].file); ast elsifnode(toks[ptr].loc,ast_elsif);
match(tok::elsif); match(tok::elsif);
match(tok::lcurve); match(tok::lcurve);
elsifnode.add(calc()); elsifnode.add(calc());
@ -1028,7 +1016,7 @@ ast parse::cond() {
node.add(std::move(elsifnode)); node.add(std::move(elsifnode));
} }
if (lookahead(tok::relse)) { if (lookahead(tok::relse)) {
ast elsenode(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_else,toks[ptr].file); ast elsenode(toks[ptr].loc,ast_else);
match(tok::relse); match(tok::relse);
elsenode.add(exprs()); elsenode.add(exprs());
node.add(std::move(elsenode)); node.add(std::move(elsenode));
@ -1037,19 +1025,19 @@ ast parse::cond() {
} }
ast parse::continue_expr() { ast parse::continue_expr() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_continue,toks[ptr].file); ast node(toks[ptr].loc,ast_continue);
match(tok::cont); match(tok::cont);
return node; return node;
} }
ast parse::break_expr() { ast parse::break_expr() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_break,toks[ptr].file); ast node(toks[ptr].loc,ast_break);
match(tok::brk); match(tok::brk);
return node; return node;
} }
ast parse::ret_expr() { ast parse::ret_expr() {
ast node(toks[ptr].tk_end_line,toks[ptr].tk_end_column,ast_ret,toks[ptr].file); ast node(toks[ptr].loc,ast_ret);
match(tok::ret); match(tok::ret);
tok type=toks[ptr].type; tok type=toks[ptr].type;
if (type==tok::tknil || type==tok::num || type==tok::str || type==tok::id || if (type==tok::tknil || type==tok::num || type==tok::str || type==tok::id ||