diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuescript/ast.cpp | 21 | ||||
| -rw-r--r-- | src/yuescript/ast.hpp | 10 | ||||
| -rw-r--r-- | src/yuescript/parser.cpp | 32 | ||||
| -rw-r--r-- | src/yuescript/parser.hpp | 17 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 3 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 66 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 38 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 8 |
8 files changed, 135 insertions, 60 deletions
diff --git a/src/yuescript/ast.cpp b/src/yuescript/ast.cpp index 239aec6..6db2c21 100644 --- a/src/yuescript/ast.cpp +++ b/src/yuescript/ast.cpp | |||
| @@ -138,4 +138,25 @@ ast_node* parse(input& i, rule& g, error_list& el, void* ud) { | |||
| 138 | return st.front(); | 138 | return st.front(); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | /** check if the start part of given input matches grammar. | ||
| 142 | The parse procedures of each rule parsed are executed | ||
| 143 | before this function returns, if parsing succeeds. | ||
| 144 | @param i input. | ||
| 145 | @param g root rule of grammar. | ||
| 146 | @param ud user data, passed to the parse procedures. | ||
| 147 | @return true on parsing success, false on failure. | ||
| 148 | */ | ||
| 149 | ast_node* start_with(input& i, rule& g, error_list& el, void* ud) { | ||
| 150 | ast_stack st; | ||
| 151 | if (!start_with(i, g, el, &st, ud)) { | ||
| 152 | for (auto node : st) { | ||
| 153 | delete node; | ||
| 154 | } | ||
| 155 | st.clear(); | ||
| 156 | return nullptr; | ||
| 157 | } | ||
| 158 | assert(st.size() == 1); | ||
| 159 | return st.front(); | ||
| 160 | } | ||
| 161 | |||
| 141 | } // namespace parserlib | 162 | } // namespace parserlib |
diff --git a/src/yuescript/ast.hpp b/src/yuescript/ast.hpp index c6da312..f59b50f 100644 --- a/src/yuescript/ast.hpp +++ b/src/yuescript/ast.hpp | |||
| @@ -597,4 +597,14 @@ private: | |||
| 597 | */ | 597 | */ |
| 598 | ast_node* parse(input& i, rule& g, error_list& el, void* ud); | 598 | ast_node* parse(input& i, rule& g, error_list& el, void* ud); |
| 599 | 599 | ||
| 600 | /** check if the start part of given input matches grammar. | ||
| 601 | The parse procedures of each rule parsed are executed | ||
| 602 | before this function returns, if parsing succeeds. | ||
| 603 | @param i input. | ||
| 604 | @param g root rule of grammar. | ||
| 605 | @param ud user data, passed to the parse procedures. | ||
| 606 | @return true on parsing success, false on failure. | ||
| 607 | */ | ||
| 608 | ast_node* start_with(input& i, rule& g, error_list& el, void* ud); | ||
| 609 | |||
| 600 | } // namespace parserlib | 610 | } // namespace parserlib |
diff --git a/src/yuescript/parser.cpp b/src/yuescript/parser.cpp index 25b735e..04b7ffd 100644 --- a/src/yuescript/parser.cpp +++ b/src/yuescript/parser.cpp | |||
| @@ -1567,10 +1567,11 @@ expr user(const expr& e, const user_handler& handler) { | |||
| 1567 | @param i input. | 1567 | @param i input. |
| 1568 | @param g root rule of grammar. | 1568 | @param g root rule of grammar. |
| 1569 | @param el list of errors. | 1569 | @param el list of errors. |
| 1570 | @param d user data, passed to the parse procedures. | 1570 | @param st ast object stack. |
| 1571 | @param ud user data, passed to the parse procedures. | ||
| 1571 | @return true on parsing success, false on failure. | 1572 | @return true on parsing success, false on failure. |
| 1572 | */ | 1573 | */ |
| 1573 | bool parse(input& i, rule& g, error_list& el, void* d, void* ud) { | 1574 | bool parse(input& i, rule& g, error_list& el, void* st, void* ud) { |
| 1574 | // prepare context | 1575 | // prepare context |
| 1575 | _context con(i, ud); | 1576 | _context con(i, ud); |
| 1576 | 1577 | ||
| @@ -1591,7 +1592,32 @@ bool parse(input& i, rule& g, error_list& el, void* d, void* ud) { | |||
| 1591 | } | 1592 | } |
| 1592 | 1593 | ||
| 1593 | // success; execute the parse procedures | 1594 | // success; execute the parse procedures |
| 1594 | con.do_parse_procs(d); | 1595 | con.do_parse_procs(st); |
| 1596 | return true; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | /** check the start part of given input. | ||
| 1600 | The parse procedures of each rule parsed are executed | ||
| 1601 | before this function returns, if parsing succeeds. | ||
| 1602 | @param i input. | ||
| 1603 | @param g root rule of grammar. | ||
| 1604 | @param el list of errors. | ||
| 1605 | @param st ast object stack. | ||
| 1606 | @param ud user data, passed to the parse procedures. | ||
| 1607 | @return true on parsing success, false on failure. | ||
| 1608 | */ | ||
| 1609 | bool start_with(input& i, rule& g, error_list& el, void* st, void* ud) { | ||
| 1610 | // prepare context | ||
| 1611 | _context con(i, ud); | ||
| 1612 | |||
| 1613 | // parse grammar | ||
| 1614 | if (!con.parse_non_term(g)) { | ||
| 1615 | el.push_back(_syntax_error(con)); | ||
| 1616 | return false; | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | // success; execute the parse procedures | ||
| 1620 | con.do_parse_procs(st); | ||
| 1595 | return true; | 1621 | return true; |
| 1596 | } | 1622 | } |
| 1597 | 1623 | ||
diff --git a/src/yuescript/parser.hpp b/src/yuescript/parser.hpp index 83682ae..d2612cd 100644 --- a/src/yuescript/parser.hpp +++ b/src/yuescript/parser.hpp | |||
| @@ -394,10 +394,23 @@ expr user(const expr& e, const user_handler& handler); | |||
| 394 | @param i input. | 394 | @param i input. |
| 395 | @param g root rule of grammar. | 395 | @param g root rule of grammar. |
| 396 | @param el list of errors. | 396 | @param el list of errors. |
| 397 | @param d user data, passed to the parse procedures. | 397 | @param st ast object stack. |
| 398 | @param ud user data, passed to the parse procedures. | ||
| 398 | @return true on parsing success, false on failure. | 399 | @return true on parsing success, false on failure. |
| 399 | */ | 400 | */ |
| 400 | bool parse(input& i, rule& g, error_list& el, void* d, void* ud); | 401 | bool parse(input& i, rule& g, error_list& el, void* st, void* ud); |
| 402 | |||
| 403 | /** check if the start part of given input matches grammar. | ||
| 404 | The parse procedures of each rule parsed are executed | ||
| 405 | before this function returns, if parsing succeeds. | ||
| 406 | @param i input. | ||
| 407 | @param g root rule of grammar. | ||
| 408 | @param el list of errors. | ||
| 409 | @param st ast object stack. | ||
| 410 | @param ud user data, passed to the parse procedures. | ||
| 411 | @return true on parsing success, false on failure. | ||
| 412 | */ | ||
| 413 | bool start_with(input& i, rule& g, error_list& el, void* st, void* ud); | ||
| 401 | 414 | ||
| 402 | /** output the specific input range to the specific stream. | 415 | /** output the specific input range to the specific stream. |
| 403 | @param stream stream. | 416 | @param stream stream. |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index acb7221..e95e35c 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
| @@ -875,8 +875,7 @@ AST_NODE(Statement) | |||
| 875 | Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t | 875 | Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t |
| 876 | > content; | 876 | > content; |
| 877 | ast_ptr<false, StatementAppendix_t> appendix; | 877 | ast_ptr<false, StatementAppendix_t> appendix; |
| 878 | ast_ptr<false, StatementSep_t> needSep; | 878 | AST_MEMBER(Statement, &sep, &comments, &content, &appendix) |
| 879 | AST_MEMBER(Statement, &sep, &comments, &content, &appendix, &needSep) | ||
| 880 | AST_END(Statement, "statement"sv) | 879 | AST_END(Statement, "statement"sv) |
| 881 | 880 | ||
| 882 | AST_NODE(Body) | 881 | AST_NODE(Body) |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 98d19a7..8574e6c 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -72,7 +72,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
| 72 | "close"s // Lua 5.4 | 72 | "close"s // Lua 5.4 |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | const std::string_view version = "0.17.0"sv; | 75 | const std::string_view version = "0.17.1"sv; |
| 76 | const std::string_view extension = "yue"sv; | 76 | const std::string_view extension = "yue"sv; |
| 77 | 77 | ||
| 78 | class CompileError : public std::logic_error { | 78 | class CompileError : public std::logic_error { |
| @@ -1497,25 +1497,6 @@ private: | |||
| 1497 | case id<ChainAssign_t>(): transformChainAssign(static_cast<ChainAssign_t*>(content), out); break; | 1497 | case id<ChainAssign_t>(): transformChainAssign(static_cast<ChainAssign_t*>(content), out); break; |
| 1498 | default: YUEE("AST node mismatch", content); break; | 1498 | default: YUEE("AST node mismatch", content); break; |
| 1499 | } | 1499 | } |
| 1500 | if (statement->needSep && !out.empty() && !out.back().empty()) { | ||
| 1501 | auto index = std::string::npos; | ||
| 1502 | if (_config.reserveLineNumber) { | ||
| 1503 | index = out.back().rfind(" -- "sv); | ||
| 1504 | } else { | ||
| 1505 | index = out.back().find_last_not_of('\n'); | ||
| 1506 | if (index != std::string::npos) index++; | ||
| 1507 | } | ||
| 1508 | if (index != std::string::npos) { | ||
| 1509 | auto ending = out.back().substr(0, index); | ||
| 1510 | auto ind = ending.find_last_of(" \t\n"sv); | ||
| 1511 | if (ind != std::string::npos) { | ||
| 1512 | ending = ending.substr(ind + 1); | ||
| 1513 | } | ||
| 1514 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | ||
| 1515 | out.back().insert(index, ";"sv); | ||
| 1516 | } | ||
| 1517 | } | ||
| 1518 | } | ||
| 1519 | } | 1500 | } |
| 1520 | 1501 | ||
| 1521 | str_list getAssignVars(ExpListAssign_t* assignment) { | 1502 | str_list getAssignVars(ExpListAssign_t* assignment) { |
| @@ -3543,8 +3524,6 @@ private: | |||
| 3543 | } | 3524 | } |
| 3544 | lst->appendix.set(stmt->appendix); | 3525 | lst->appendix.set(stmt->appendix); |
| 3545 | stmt->appendix.set(nullptr); | 3526 | stmt->appendix.set(nullptr); |
| 3546 | lst->needSep.set(stmt->needSep); | ||
| 3547 | stmt->needSep.set(nullptr); | ||
| 3548 | auto exp = lastExpFromStatement(lst); | 3527 | auto exp = lastExpFromStatement(lst); |
| 3549 | BREAK_IF(!exp); | 3528 | BREAK_IF(!exp); |
| 3550 | for (auto val : pipeBody->values.objects()) { | 3529 | for (auto val : pipeBody->values.objects()) { |
| @@ -3753,22 +3732,6 @@ private: | |||
| 3753 | returnNode->valueList.set(expListLow); | 3732 | returnNode->valueList.set(expListLow); |
| 3754 | returnNode->allowBlockMacroReturn = true; | 3733 | returnNode->allowBlockMacroReturn = true; |
| 3755 | last->content.set(returnNode); | 3734 | last->content.set(returnNode); |
| 3756 | last->needSep.set(nullptr); | ||
| 3757 | auto bLast = ++nodes.rbegin(); | ||
| 3758 | if (bLast != nodes.rend()) { | ||
| 3759 | bool isMacro = false; | ||
| 3760 | BLOCK_START | ||
| 3761 | BREAK_IF(expListLow->exprs.size() != 1); | ||
| 3762 | auto exp = static_cast<Exp_t*>(expListLow->exprs.back()); | ||
| 3763 | BREAK_IF(!exp->opValues.empty()); | ||
| 3764 | auto chainValue = exp->getByPath<UnaryExp_t, Value_t, ChainValue_t>(); | ||
| 3765 | BREAK_IF(!chainValue); | ||
| 3766 | isMacro = isMacroChain(chainValue); | ||
| 3767 | BLOCK_END | ||
| 3768 | if (!isMacro) { | ||
| 3769 | ast_to<Statement_t>(*bLast)->needSep.set(nullptr); | ||
| 3770 | } | ||
| 3771 | } | ||
| 3772 | BLOCK_END | 3735 | BLOCK_END |
| 3773 | break; | 3736 | break; |
| 3774 | } | 3737 | } |
| @@ -3802,11 +3765,6 @@ private: | |||
| 3802 | } | 3765 | } |
| 3803 | newAssignment->action.set(assign); | 3766 | newAssignment->action.set(assign); |
| 3804 | last->content.set(newAssignment); | 3767 | last->content.set(newAssignment); |
| 3805 | last->needSep.set(nullptr); | ||
| 3806 | auto bLast = ++nodes.rbegin(); | ||
| 3807 | if (bLast != nodes.rend()) { | ||
| 3808 | static_cast<Statement_t*>(*bLast)->needSep.set(nullptr); | ||
| 3809 | } | ||
| 3810 | } else if (!last->content.is<BreakLoop_t>()) { | 3768 | } else if (!last->content.is<BreakLoop_t>()) { |
| 3811 | throw CompileError("expecting assignable statement or break loop"sv, last); | 3769 | throw CompileError("expecting assignable statement or break loop"sv, last); |
| 3812 | } | 3770 | } |
| @@ -3818,6 +3776,28 @@ private: | |||
| 3818 | str_list temp; | 3776 | str_list temp; |
| 3819 | for (auto node : nodes) { | 3777 | for (auto node : nodes) { |
| 3820 | transformStatement(static_cast<Statement_t*>(node), temp); | 3778 | transformStatement(static_cast<Statement_t*>(node), temp); |
| 3779 | if (_parser.startWith<StatementSep_t>(temp.back())) { | ||
| 3780 | auto rit = ++temp.rbegin(); | ||
| 3781 | if (rit != temp.rend() && !rit->empty()) { | ||
| 3782 | auto index = std::string::npos; | ||
| 3783 | if (_config.reserveLineNumber) { | ||
| 3784 | index = rit->rfind(" -- "sv); | ||
| 3785 | } else { | ||
| 3786 | index = rit->find_last_not_of('\n'); | ||
| 3787 | if (index != std::string::npos) index++; | ||
| 3788 | } | ||
| 3789 | if (index != std::string::npos) { | ||
| 3790 | auto ending = rit->substr(0, index); | ||
| 3791 | auto ind = ending.find_last_of(" \t\n"sv); | ||
| 3792 | if (ind != std::string::npos) { | ||
| 3793 | ending = ending.substr(ind + 1); | ||
| 3794 | } | ||
| 3795 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | ||
| 3796 | rit->insert(index, ";"sv); | ||
| 3797 | } | ||
| 3798 | } | ||
| 3799 | } | ||
| 3800 | } | ||
| 3821 | } | 3801 | } |
| 3822 | out.push_back(join(temp)); | 3802 | out.push_back(join(temp)); |
| 3823 | } else { | 3803 | } else { |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index f383275..f72407d 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -853,13 +853,6 @@ YueParser::YueParser() { | |||
| 853 | ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; | 853 | ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; |
| 854 | 854 | ||
| 855 | StatementAppendix = (IfLine | WhileLine | CompInner) >> space; | 855 | StatementAppendix = (IfLine | WhileLine | CompInner) >> space; |
| 856 | StatementSep = and_( | ||
| 857 | *space_break >> check_indent_match >> space >> ( | ||
| 858 | set("($'\"") | | ||
| 859 | "[[" | | ||
| 860 | "[=" | ||
| 861 | ) | ||
| 862 | ); | ||
| 863 | Statement = | 856 | Statement = |
| 864 | Seperator >> | 857 | Seperator >> |
| 865 | -( | 858 | -( |
| @@ -876,8 +869,9 @@ YueParser::YueParser() { | |||
| 876 | StatementAppendix >> empty_block_error | 869 | StatementAppendix >> empty_block_error |
| 877 | ) >> | 870 | ) >> |
| 878 | space >> | 871 | space >> |
| 879 | -StatementAppendix >> | 872 | -StatementAppendix; |
| 880 | -StatementSep; | 873 | |
| 874 | StatementSep = white >> (set("('\"") | "[[" | "[="); | ||
| 881 | 875 | ||
| 882 | Body = in_block | Statement; | 876 | Body = in_block | Statement; |
| 883 | 877 | ||
| @@ -905,6 +899,32 @@ YueParser::YueParser() { | |||
| 905 | } | 899 | } |
| 906 | // clang-format on | 900 | // clang-format on |
| 907 | 901 | ||
| 902 | bool YueParser::startWith(std::string_view codes, rule& r) { | ||
| 903 | std::unique_ptr<input> converted; | ||
| 904 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { | ||
| 905 | codes = codes.substr(3); | ||
| 906 | } | ||
| 907 | try { | ||
| 908 | if (!codes.empty()) { | ||
| 909 | converted = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); | ||
| 910 | } else { | ||
| 911 | converted = std::make_unique<input>(); | ||
| 912 | } | ||
| 913 | } catch (const std::range_error&) { | ||
| 914 | return false; | ||
| 915 | } | ||
| 916 | error_list errors; | ||
| 917 | try { | ||
| 918 | State state; | ||
| 919 | return ::yue::start_with(*converted, r, errors, &state); | ||
| 920 | } catch (const ParserError&) { | ||
| 921 | return false; | ||
| 922 | } catch (const std::logic_error&) { | ||
| 923 | return false; | ||
| 924 | } | ||
| 925 | return true; | ||
| 926 | } | ||
| 927 | |||
| 908 | ParseInfo YueParser::parse(std::string_view codes, rule& r) { | 928 | ParseInfo YueParser::parse(std::string_view codes, rule& r) { |
| 909 | ParseInfo res; | 929 | ParseInfo res; |
| 910 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { | 930 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index d4f66eb..d7fbf90 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
| @@ -84,11 +84,17 @@ public: | |||
| 84 | return parse(codes, rEnd).node; | 84 | return parse(codes, rEnd).node; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | template <class AST> | ||
| 88 | bool startWith(std::string_view codes) { | ||
| 89 | return startWith(codes, getRule<AST>()); | ||
| 90 | } | ||
| 91 | |||
| 87 | std::string toString(ast_node* node); | 92 | std::string toString(ast_node* node); |
| 88 | std::string toString(input::iterator begin, input::iterator end); | 93 | std::string toString(input::iterator begin, input::iterator end); |
| 89 | 94 | ||
| 90 | protected: | 95 | protected: |
| 91 | ParseInfo parse(std::string_view codes, rule& r); | 96 | ParseInfo parse(std::string_view codes, rule& r); |
| 97 | bool startWith(std::string_view codes, rule& r); | ||
| 92 | 98 | ||
| 93 | struct State { | 99 | struct State { |
| 94 | State() { | 100 | State() { |
| @@ -387,8 +393,8 @@ private: | |||
| 387 | AST_RULE(WhileLine) | 393 | AST_RULE(WhileLine) |
| 388 | AST_RULE(BreakLoop) | 394 | AST_RULE(BreakLoop) |
| 389 | AST_RULE(StatementAppendix) | 395 | AST_RULE(StatementAppendix) |
| 390 | AST_RULE(StatementSep) | ||
| 391 | AST_RULE(Statement) | 396 | AST_RULE(Statement) |
| 397 | AST_RULE(StatementSep); | ||
| 392 | AST_RULE(YueLineComment) | 398 | AST_RULE(YueLineComment) |
| 393 | AST_RULE(MultilineCommentInner) | 399 | AST_RULE(MultilineCommentInner) |
| 394 | AST_RULE(YueMultilineComment) | 400 | AST_RULE(YueMultilineComment) |
