diff options
author | Li Jin <dragon-fly@qq.com> | 2022-11-07 18:22:13 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-11-09 11:29:32 +0800 |
commit | e62eb9537df808ca461917cccea14e662312c775 (patch) | |
tree | 0b1eb2f756e8b77f99dc463a54c5be55cca1cea1 | |
parent | fbdf356c7ac688da385edfc23e9d8bb3e6c87a00 (diff) | |
download | yuescript-e62eb9537df808ca461917cccea14e662312c775.tar.gz yuescript-e62eb9537df808ca461917cccea14e662312c775.tar.bz2 yuescript-e62eb9537df808ca461917cccea14e662312c775.zip |
start to add error AST reporting.
-rw-r--r-- | src/yuescript/parser.cpp | 4 | ||||
-rw-r--r-- | src/yuescript/parser.hpp | 14 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | src/yuescript/yue_parser.cpp | 50 | ||||
-rw-r--r--[-rwxr-xr-x] | src/yuescript/yue_parser.h | 14 |
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; | |||
36 | class _context; | 36 | class _context; |
37 | class rule; | 37 | class rule; |
38 | 38 | ||
39 | struct item_t { | ||
40 | input_it begin; | ||
41 | input_it end; | ||
42 | void* user_data; | ||
43 | }; | ||
44 | typedef std::function<bool(const item_t&)> user_handler; | ||
45 | |||
46 | /// position into the input. | 39 | /// position into the input. |
47 | class pos { | 40 | class pos { |
48 | public: | 41 | public: |
@@ -66,6 +59,13 @@ public: | |||
66 | pos(input& i); | 59 | pos(input& i); |
67 | }; | 60 | }; |
68 | 61 | ||
62 | struct item_t { | ||
63 | pos* begin; | ||
64 | pos* end; | ||
65 | void* user_data; | ||
66 | }; | ||
67 | typedef std::function<bool(const item_t&)> user_handler; | ||
68 | |||
69 | /** a grammar expression. | 69 | /** a grammar expression. |
70 | */ | 70 | */ |
71 | class expr { | 71 | class 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 | ||
61 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
62 | 62 | ||
63 | const std::string_view version = "0.15.7"sv; | 63 | const std::string_view version = "0.15.8"sv; |
64 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
65 | 65 | ||
66 | class YueCompilerImpl { | 66 | class 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 | ||
38 | class ParserError : public std::logic_error { | ||
39 | public: | ||
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 | |||
38 | template <typename T> | 50 | template <typename T> |
39 | struct identity { typedef T type; }; | 51 | struct 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; |