aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2022-11-07 18:22:13 +0800
committerLi Jin <dragon-fly@qq.com>2022-11-09 11:29:32 +0800
commite62eb9537df808ca461917cccea14e662312c775 (patch)
tree0b1eb2f756e8b77f99dc463a54c5be55cca1cea1
parentfbdf356c7ac688da385edfc23e9d8bb3e6c87a00 (diff)
downloadyuescript-e62eb9537df808ca461917cccea14e662312c775.tar.gz
yuescript-e62eb9537df808ca461917cccea14e662312c775.tar.bz2
yuescript-e62eb9537df808ca461917cccea14e662312c775.zip
start to add error AST reporting.
-rw-r--r--src/yuescript/parser.cpp4
-rw-r--r--src/yuescript/parser.hpp14
-rw-r--r--src/yuescript/yue_compiler.cpp2
-rw-r--r--[-rwxr-xr-x]src/yuescript/yue_parser.cpp50
-rw-r--r--[-rwxr-xr-x]src/yuescript/yue_parser.h14
5 files changed, 54 insertions, 30 deletions
diff --git a/src/yuescript/parser.cpp b/src/yuescript/parser.cpp
index a6eb513..5939793 100644
--- a/src/yuescript/parser.cpp
+++ b/src/yuescript/parser.cpp
@@ -381,7 +381,7 @@ public:
381 virtual bool parse_non_term(_context& con) const { 381 virtual bool parse_non_term(_context& con) const {
382 pos pos = con.m_pos; 382 pos pos = con.m_pos;
383 if (m_expr->parse_non_term(con)) { 383 if (m_expr->parse_non_term(con)) {
384 item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data}; 384 item_t item = {&pos, &con.m_pos, con.m_user_data};
385 return m_handler(item); 385 return m_handler(item);
386 } 386 }
387 return false; 387 return false;
@@ -391,7 +391,7 @@ public:
391 virtual bool parse_term(_context& con) const { 391 virtual bool parse_term(_context& con) const {
392 pos pos = con.m_pos; 392 pos pos = con.m_pos;
393 if (m_expr->parse_term(con)) { 393 if (m_expr->parse_term(con)) {
394 item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data}; 394 item_t item = {&pos, &con.m_pos, con.m_user_data};
395 return m_handler(item); 395 return m_handler(item);
396 } 396 }
397 return false; 397 return false;
diff --git a/src/yuescript/parser.hpp b/src/yuescript/parser.hpp
index eed0bff..7bec5d5 100644
--- a/src/yuescript/parser.hpp
+++ b/src/yuescript/parser.hpp
@@ -36,13 +36,6 @@ class _expr;
36class _context; 36class _context;
37class rule; 37class rule;
38 38
39struct item_t {
40 input_it begin;
41 input_it end;
42 void* user_data;
43};
44typedef std::function<bool(const item_t&)> user_handler;
45
46/// position into the input. 39/// position into the input.
47class pos { 40class pos {
48public: 41public:
@@ -66,6 +59,13 @@ public:
66 pos(input& i); 59 pos(input& i);
67}; 60};
68 61
62struct item_t {
63 pos* begin;
64 pos* end;
65 void* user_data;
66};
67typedef std::function<bool(const item_t&)> user_handler;
68
69/** a grammar expression. 69/** a grammar expression.
70 */ 70 */
71class expr { 71class expr {
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 22a4a02..e061604 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -60,7 +60,7 @@ namespace yue {
60 60
61typedef std::list<std::string> str_list; 61typedef std::list<std::string> str_list;
62 62
63const std::string_view version = "0.15.7"sv; 63const std::string_view version = "0.15.8"sv;
64const std::string_view extension = "yue"sv; 64const std::string_view extension = "yue"sv;
65 65
66class YueCompilerImpl { 66class YueCompilerImpl {
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 07fcd27..b134ee2 100755..100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -71,6 +71,11 @@ YueParser::YueParser() {
71 Cut = false_(); 71 Cut = false_();
72 Seperator = true_(); 72 Seperator = true_();
73 73
74 invalid_empty_block = pl::user(true_(), [](const item_t& item) {
75 throw ParserError("must be followed by a statement or an indented block", *item.begin, *item.end);
76 return false;
77 });
78
74 #define sym(str) (Space >> str) 79 #define sym(str) (Space >> str)
75 #define symx(str) expr(str) 80 #define symx(str) expr(str)
76 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> Cut) 81 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> Cut)
@@ -79,12 +84,13 @@ YueParser::YueParser() {
79 #define disable_chain(patt) (DisableChain >> ((patt) >> EnableChain | EnableChain >> Cut)) 84 #define disable_chain(patt) (DisableChain >> ((patt) >> EnableChain | EnableChain >> Cut))
80 #define disable_do_chain_arg_table_block(patt) (DisableDoChainArgTableBlock >> ((patt) >> EnableDoChainArgTableBlock | EnableDoChainArgTableBlock >> Cut)) 85 #define disable_do_chain_arg_table_block(patt) (DisableDoChainArgTableBlock >> ((patt) >> EnableDoChainArgTableBlock | EnableDoChainArgTableBlock >> Cut))
81 #define disable_arg_table_block(patt) (DisableArgTableBlock >> ((patt) >> EnableArgTableBlock | EnableArgTableBlock >> Cut)) 86 #define disable_arg_table_block(patt) (DisableArgTableBlock >> ((patt) >> EnableArgTableBlock | EnableArgTableBlock >> Cut))
82 #define plain_body_with(str) (-(Space >> key(str)) >> InBlock | Space >> key(str) >> Space >> Statement) 87 #define body_with(str) (Space >> (key(str) >> Space >> (InBlock | Statement) | InBlock | invalid_empty_block))
83 #define plain_body (InBlock | Space >> Statement) 88 #define opt_body_with(str) (Space >> (key(str) >> Space >> (InBlock | Statement) | InBlock))
89 #define body (Space >> (InBlock | Statement | invalid_empty_block))
84 90
85 Variable = pl::user(Name, [](const item_t& item) { 91 Variable = pl::user(Name, [](const item_t& item) {
86 State* st = reinterpret_cast<State*>(item.user_data); 92 State* st = reinterpret_cast<State*>(item.user_data);
87 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it); 93 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it);
88 auto isValid = Keywords.find(st->buffer) == Keywords.end(); 94 auto isValid = Keywords.find(st->buffer) == Keywords.end();
89 if (isValid) { 95 if (isValid) {
90 if (st->buffer == st->moduleName) { 96 if (st->buffer == st->moduleName) {
@@ -98,7 +104,7 @@ YueParser::YueParser() {
98 104
99 LabelName = pl::user(Name, [](const item_t& item) { 105 LabelName = pl::user(Name, [](const item_t& item) {
100 State* st = reinterpret_cast<State*>(item.user_data); 106 State* st = reinterpret_cast<State*>(item.user_data);
101 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it); 107 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it);
102 auto isValid = LuaKeywords.find(st->buffer) == LuaKeywords.end(); 108 auto isValid = LuaKeywords.find(st->buffer) == LuaKeywords.end();
103 st->buffer.clear(); 109 st->buffer.clear();
104 return isValid; 110 return isValid;
@@ -106,7 +112,7 @@ YueParser::YueParser() {
106 112
107 LuaKeyword = pl::user(Name, [](const item_t& item) { 113 LuaKeyword = pl::user(Name, [](const item_t& item) {
108 State* st = reinterpret_cast<State*>(item.user_data); 114 State* st = reinterpret_cast<State*>(item.user_data);
109 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it); 115 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it);
110 auto it = LuaKeywords.find(st->buffer); 116 auto it = LuaKeywords.find(st->buffer);
111 st->buffer.clear(); 117 st->buffer.clear();
112 return it != LuaKeywords.end(); 118 return it != LuaKeywords.end();
@@ -123,7 +129,7 @@ YueParser::YueParser() {
123 129
124 check_indent = pl::user(Indent, [](const item_t& item) { 130 check_indent = pl::user(Indent, [](const item_t& item) {
125 int indent = 0; 131 int indent = 0;
126 for (input_it i = item.begin; i != item.end; ++i) { 132 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
127 switch (*i) { 133 switch (*i) {
128 case ' ': indent++; break; 134 case ' ': indent++; break;
129 case '\t': indent += 4; break; 135 case '\t': indent += 4; break;
@@ -136,7 +142,7 @@ YueParser::YueParser() {
136 142
137 advance = pl::user(Indent, [](const item_t& item) { 143 advance = pl::user(Indent, [](const item_t& item) {
138 int indent = 0; 144 int indent = 0;
139 for (input_it i = item.begin; i != item.end; ++i) { 145 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
140 switch (*i) { 146 switch (*i) {
141 case ' ': indent++; break; 147 case ' ': indent++; break;
142 case '\t': indent += 4; break; 148 case '\t': indent += 4; break;
@@ -154,7 +160,7 @@ YueParser::YueParser() {
154 160
155 push_indent = pl::user(Indent, [](const item_t& item) { 161 push_indent = pl::user(Indent, [](const item_t& item) {
156 int indent = 0; 162 int indent = 0;
157 for (input_it i = item.begin; i != item.end; ++i) { 163 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
158 switch (*i) { 164 switch (*i) {
159 case ' ': indent++; break; 165 case ' ': indent++; break;
160 case '\t': indent += 4; break; 166 case '\t': indent += 4; break;
@@ -232,9 +238,9 @@ YueParser::YueParser() {
232 238
233 WithExp = ExpList >> -Assign; 239 WithExp = ExpList >> -Assign;
234 240
235 With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> plain_body_with("do"); 241 With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> body_with("do");
236 SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(SwitchList)) >> plain_body_with("then"); 242 SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(SwitchList)) >> body_with("then");
237 SwitchElse = Space >> key("else") >> plain_body; 243 SwitchElse = Space >> key("else") >> body;
238 244
239 SwitchBlock = *EmptyLine >> 245 SwitchBlock = *EmptyLine >>
240 Advance >> Seperator >> 246 Advance >> Seperator >>
@@ -251,24 +257,24 @@ YueParser::YueParser() {
251 257
252 assignment = ExpList >> Assign; 258 assignment = ExpList >> Assign;
253 IfCond = disable_chain(disable_arg_table_block(assignment | Exp)); 259 IfCond = disable_chain(disable_arg_table_block(assignment | Exp));
254 IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("elseif") >> IfCond >> plain_body_with("then"); 260 IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("elseif") >> IfCond >> body_with("then");
255 IfElse = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("else") >> plain_body; 261 IfElse = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("else") >> body;
256 IfType = (expr("if") | expr("unless")) >> not_(AlphaNum); 262 IfType = (expr("if") | expr("unless")) >> not_(AlphaNum);
257 If = Space >> IfType >> IfCond >> plain_body_with("then") >> *IfElseIf >> -IfElse; 263 If = Space >> IfType >> IfCond >> opt_body_with("then") >> *IfElseIf >> -IfElse;
258 264
259 WhileType = (expr("while") | expr("until")) >> not_(AlphaNum); 265 WhileType = (expr("while") | expr("until")) >> not_(AlphaNum);
260 While = WhileType >> disable_do_chain_arg_table_block(Exp) >> plain_body_with("do"); 266 While = WhileType >> disable_do_chain_arg_table_block(Exp) >> opt_body_with("do");
261 Repeat = key("repeat") >> Body >> Break >> *EmptyLine >> CheckIndent >> Space >> key("until") >> Exp; 267 Repeat = key("repeat") >> Body >> Break >> *EmptyLine >> CheckIndent >> Space >> key("until") >> Exp;
262 268
263 for_step_value = sym(',') >> Exp; 269 for_step_value = sym(',') >> Exp;
264 for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value; 270 for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
265 271
266 For = key("for") >> disable_do_chain_arg_table_block(for_args) >> plain_body_with("do"); 272 For = key("for") >> disable_do_chain_arg_table_block(for_args) >> opt_body_with("do");
267 273
268 for_in = star_exp | ExpList; 274 for_in = star_exp | ExpList;
269 275
270 ForEach = key("for") >> AssignableNameList >> Space >> key("in") >> 276 ForEach = key("for") >> AssignableNameList >> Space >> key("in") >>
271 disable_do_chain_arg_table_block(for_in) >> plain_body_with("do"); 277 disable_do_chain_arg_table_block(for_in) >> opt_body_with("do");
272 278
273 Do = pl::user(Space >> key("do"), [](const item_t& item) { 279 Do = pl::user(Space >> key("do"), [](const item_t& item) {
274 State* st = reinterpret_cast<State*>(item.user_data); 280 State* st = reinterpret_cast<State*>(item.user_data);
@@ -413,14 +419,14 @@ YueParser::YueParser() {
413 lua_string_close = ']' >> *expr('=') >> ']'; 419 lua_string_close = ']' >> *expr('=') >> ']';
414 420
415 LuaStringOpen = pl::user(lua_string_open, [](const item_t& item) { 421 LuaStringOpen = pl::user(lua_string_open, [](const item_t& item) {
416 size_t count = std::distance(item.begin, item.end); 422 size_t count = std::distance(item.begin->m_it, item.end->m_it);
417 State* st = reinterpret_cast<State*>(item.user_data); 423 State* st = reinterpret_cast<State*>(item.user_data);
418 st->stringOpen = count; 424 st->stringOpen = count;
419 return true; 425 return true;
420 }); 426 });
421 427
422 LuaStringClose = pl::user(lua_string_close, [](const item_t& item) { 428 LuaStringClose = pl::user(lua_string_close, [](const item_t& item) {
423 size_t count = std::distance(item.begin, item.end); 429 size_t count = std::distance(item.begin->m_it, item.end->m_it);
424 State* st = reinterpret_cast<State*>(item.user_data); 430 State* st = reinterpret_cast<State*>(item.user_data);
425 return st->stringOpen == count; 431 return st->stringOpen == count;
426 }); 432 });
@@ -655,7 +661,8 @@ YueParser::YueParser() {
655 Import | While | Repeat | For | ForEach | 661 Import | While | Repeat | For | ForEach |
656 Return | Local | Global | Export | Macro | 662 Return | Local | Global | Export | Macro |
657 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | 663 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending |
658 LocalAttrib | Backcall | PipeBody | ExpListAssign 664 LocalAttrib | Backcall | PipeBody | ExpListAssign |
665 statement_appendix >> invalid_empty_block
659 ) >> Space >> 666 ) >> Space >>
660 -statement_appendix >> -statement_sep; 667 -statement_appendix >> -statement_sep;
661 668
@@ -699,6 +706,9 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
699 res.exportDefault = state.exportDefault; 706 res.exportDefault = state.exportDefault;
700 res.exportMacro = state.exportMacro; 707 res.exportMacro = state.exportMacro;
701 } 708 }
709 } catch (const ParserError& err) {
710 res.error = res.errorMessage(err.what(), &err.loc);
711 return res;
702 } catch (const std::logic_error& err) { 712 } catch (const std::logic_error& err) {
703 res.error = err.what(); 713 res.error = err.what();
704 return res; 714 return res;
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 750341b..461b381 100755..100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -35,6 +35,18 @@ struct ParseInfo {
35 std::string errorMessage(std::string_view msg, const input_range* loc) const; 35 std::string errorMessage(std::string_view msg, const input_range* loc) const;
36}; 36};
37 37
38class ParserError : public std::logic_error {
39public:
40 explicit ParserError(const std::string& msg, const pos& begin, const pos& end)
41 : std::logic_error(msg)
42 , loc(begin, end) { }
43
44 explicit ParserError(const char* msg, const pos& begin, const pos& end)
45 : std::logic_error(msg)
46 , loc(begin, end) { }
47 input_range loc;
48};
49
38template <typename T> 50template <typename T>
39struct identity { typedef T type; }; 51struct identity { typedef T type; };
40 52
@@ -101,6 +113,8 @@ private:
101 return Cut; 113 return Cut;
102 } 114 }
103 115
116 rule invalid_empty_block;
117
104 rule num_char; 118 rule num_char;
105 rule num_char_hex; 119 rule num_char_hex;
106 rule num_lit; 120 rule num_lit;