From e62eb9537df808ca461917cccea14e662312c775 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 7 Nov 2022 18:22:13 +0800 Subject: start to add error AST reporting. --- src/yuescript/parser.cpp | 4 ++-- src/yuescript/parser.hpp | 14 ++++++------ src/yuescript/yue_compiler.cpp | 2 +- src/yuescript/yue_parser.cpp | 50 +++++++++++++++++++++++++----------------- src/yuescript/yue_parser.h | 14 ++++++++++++ 5 files changed, 54 insertions(+), 30 deletions(-) mode change 100755 => 100644 src/yuescript/yue_parser.cpp mode change 100755 => 100644 src/yuescript/yue_parser.h 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: virtual bool parse_non_term(_context& con) const { pos pos = con.m_pos; if (m_expr->parse_non_term(con)) { - item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data}; + item_t item = {&pos, &con.m_pos, con.m_user_data}; return m_handler(item); } return false; @@ -391,7 +391,7 @@ public: virtual bool parse_term(_context& con) const { pos pos = con.m_pos; if (m_expr->parse_term(con)) { - item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data}; + item_t item = {&pos, &con.m_pos, con.m_user_data}; return m_handler(item); } 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; class _context; class rule; -struct item_t { - input_it begin; - input_it end; - void* user_data; -}; -typedef std::function user_handler; - /// position into the input. class pos { public: @@ -66,6 +59,13 @@ public: pos(input& i); }; +struct item_t { + pos* begin; + pos* end; + void* user_data; +}; +typedef std::function user_handler; + /** a grammar expression. */ 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 { typedef std::list str_list; -const std::string_view version = "0.15.7"sv; +const std::string_view version = "0.15.8"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp old mode 100755 new mode 100644 index 07fcd27..b134ee2 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -71,6 +71,11 @@ YueParser::YueParser() { Cut = false_(); Seperator = true_(); + invalid_empty_block = pl::user(true_(), [](const item_t& item) { + throw ParserError("must be followed by a statement or an indented block", *item.begin, *item.end); + return false; + }); + #define sym(str) (Space >> str) #define symx(str) expr(str) #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> Cut) @@ -79,12 +84,13 @@ YueParser::YueParser() { #define disable_chain(patt) (DisableChain >> ((patt) >> EnableChain | EnableChain >> Cut)) #define disable_do_chain_arg_table_block(patt) (DisableDoChainArgTableBlock >> ((patt) >> EnableDoChainArgTableBlock | EnableDoChainArgTableBlock >> Cut)) #define disable_arg_table_block(patt) (DisableArgTableBlock >> ((patt) >> EnableArgTableBlock | EnableArgTableBlock >> Cut)) - #define plain_body_with(str) (-(Space >> key(str)) >> InBlock | Space >> key(str) >> Space >> Statement) - #define plain_body (InBlock | Space >> Statement) + #define body_with(str) (Space >> (key(str) >> Space >> (InBlock | Statement) | InBlock | invalid_empty_block)) + #define opt_body_with(str) (Space >> (key(str) >> Space >> (InBlock | Statement) | InBlock)) + #define body (Space >> (InBlock | Statement | invalid_empty_block)) Variable = pl::user(Name, [](const item_t& item) { State* st = reinterpret_cast(item.user_data); - for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast(*it); + for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast(*it); auto isValid = Keywords.find(st->buffer) == Keywords.end(); if (isValid) { if (st->buffer == st->moduleName) { @@ -98,7 +104,7 @@ YueParser::YueParser() { LabelName = pl::user(Name, [](const item_t& item) { State* st = reinterpret_cast(item.user_data); - for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast(*it); + for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast(*it); auto isValid = LuaKeywords.find(st->buffer) == LuaKeywords.end(); st->buffer.clear(); return isValid; @@ -106,7 +112,7 @@ YueParser::YueParser() { LuaKeyword = pl::user(Name, [](const item_t& item) { State* st = reinterpret_cast(item.user_data); - for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast(*it); + for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast(*it); auto it = LuaKeywords.find(st->buffer); st->buffer.clear(); return it != LuaKeywords.end(); @@ -123,7 +129,7 @@ YueParser::YueParser() { check_indent = pl::user(Indent, [](const item_t& item) { int indent = 0; - for (input_it i = item.begin; i != item.end; ++i) { + for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { switch (*i) { case ' ': indent++; break; case '\t': indent += 4; break; @@ -136,7 +142,7 @@ YueParser::YueParser() { advance = pl::user(Indent, [](const item_t& item) { int indent = 0; - for (input_it i = item.begin; i != item.end; ++i) { + for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { switch (*i) { case ' ': indent++; break; case '\t': indent += 4; break; @@ -154,7 +160,7 @@ YueParser::YueParser() { push_indent = pl::user(Indent, [](const item_t& item) { int indent = 0; - for (input_it i = item.begin; i != item.end; ++i) { + for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { switch (*i) { case ' ': indent++; break; case '\t': indent += 4; break; @@ -232,9 +238,9 @@ YueParser::YueParser() { WithExp = ExpList >> -Assign; - With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> plain_body_with("do"); - SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(SwitchList)) >> plain_body_with("then"); - SwitchElse = Space >> key("else") >> plain_body; + With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> body_with("do"); + SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(SwitchList)) >> body_with("then"); + SwitchElse = Space >> key("else") >> body; SwitchBlock = *EmptyLine >> Advance >> Seperator >> @@ -251,24 +257,24 @@ YueParser::YueParser() { assignment = ExpList >> Assign; IfCond = disable_chain(disable_arg_table_block(assignment | Exp)); - IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("elseif") >> IfCond >> plain_body_with("then"); - IfElse = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("else") >> plain_body; + IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("elseif") >> IfCond >> body_with("then"); + IfElse = -(Break >> *EmptyLine >> CheckIndent) >> Space >> key("else") >> body; IfType = (expr("if") | expr("unless")) >> not_(AlphaNum); - If = Space >> IfType >> IfCond >> plain_body_with("then") >> *IfElseIf >> -IfElse; + If = Space >> IfType >> IfCond >> opt_body_with("then") >> *IfElseIf >> -IfElse; WhileType = (expr("while") | expr("until")) >> not_(AlphaNum); - While = WhileType >> disable_do_chain_arg_table_block(Exp) >> plain_body_with("do"); + While = WhileType >> disable_do_chain_arg_table_block(Exp) >> opt_body_with("do"); Repeat = key("repeat") >> Body >> Break >> *EmptyLine >> CheckIndent >> Space >> key("until") >> Exp; for_step_value = sym(',') >> Exp; for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value; - For = key("for") >> disable_do_chain_arg_table_block(for_args) >> plain_body_with("do"); + For = key("for") >> disable_do_chain_arg_table_block(for_args) >> opt_body_with("do"); for_in = star_exp | ExpList; ForEach = key("for") >> AssignableNameList >> Space >> key("in") >> - disable_do_chain_arg_table_block(for_in) >> plain_body_with("do"); + disable_do_chain_arg_table_block(for_in) >> opt_body_with("do"); Do = pl::user(Space >> key("do"), [](const item_t& item) { State* st = reinterpret_cast(item.user_data); @@ -413,14 +419,14 @@ YueParser::YueParser() { lua_string_close = ']' >> *expr('=') >> ']'; LuaStringOpen = pl::user(lua_string_open, [](const item_t& item) { - size_t count = std::distance(item.begin, item.end); + size_t count = std::distance(item.begin->m_it, item.end->m_it); State* st = reinterpret_cast(item.user_data); st->stringOpen = count; return true; }); LuaStringClose = pl::user(lua_string_close, [](const item_t& item) { - size_t count = std::distance(item.begin, item.end); + size_t count = std::distance(item.begin->m_it, item.end->m_it); State* st = reinterpret_cast(item.user_data); return st->stringOpen == count; }); @@ -655,7 +661,8 @@ YueParser::YueParser() { Import | While | Repeat | For | ForEach | Return | Local | Global | Export | Macro | MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | - LocalAttrib | Backcall | PipeBody | ExpListAssign + LocalAttrib | Backcall | PipeBody | ExpListAssign | + statement_appendix >> invalid_empty_block ) >> Space >> -statement_appendix >> -statement_sep; @@ -699,6 +706,9 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { res.exportDefault = state.exportDefault; res.exportMacro = state.exportMacro; } + } catch (const ParserError& err) { + res.error = res.errorMessage(err.what(), &err.loc); + return res; } catch (const std::logic_error& err) { res.error = err.what(); return res; diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h old mode 100755 new mode 100644 index 750341b..461b381 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -35,6 +35,18 @@ struct ParseInfo { std::string errorMessage(std::string_view msg, const input_range* loc) const; }; +class ParserError : public std::logic_error { +public: + explicit ParserError(const std::string& msg, const pos& begin, const pos& end) + : std::logic_error(msg) + , loc(begin, end) { } + + explicit ParserError(const char* msg, const pos& begin, const pos& end) + : std::logic_error(msg) + , loc(begin, end) { } + input_range loc; +}; + template struct identity { typedef T type; }; @@ -101,6 +113,8 @@ private: return Cut; } + rule invalid_empty_block; + rule num_char; rule num_char_hex; rule num_lit; -- cgit v1.2.3-55-g6feb