aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-06-25 17:46:32 +0800
committerLi Jin <dragon-fly@qq.com>2023-06-25 17:46:32 +0800
commitcd618f934b0e4a30bd6cd4e98f8c1005bf3d6193 (patch)
tree5bc8bc55f80fe74a3b73101b55eabc60ae1d75c3 /src
parent5d246757285a437401347dd6a1a1f8d3cf61e08c (diff)
downloadyuescript-cd618f934b0e4a30bd6cd4e98f8c1005bf3d6193.tar.gz
yuescript-cd618f934b0e4a30bd6cd4e98f8c1005bf3d6193.tar.bz2
yuescript-cd618f934b0e4a30bd6cd4e98f8c1005bf3d6193.zip
fix more ambiguous Lua codes generation cases.
Diffstat (limited to 'src')
-rw-r--r--src/yuescript/ast.cpp21
-rw-r--r--src/yuescript/ast.hpp10
-rw-r--r--src/yuescript/parser.cpp32
-rw-r--r--src/yuescript/parser.hpp17
-rw-r--r--src/yuescript/yue_ast.h3
-rw-r--r--src/yuescript/yue_compiler.cpp66
-rw-r--r--src/yuescript/yue_parser.cpp38
-rw-r--r--src/yuescript/yue_parser.h8
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*/
149ast_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*/
598ast_node* parse(input& i, rule& g, error_list& el, void* ud); 598ast_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*/
608ast_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*/
1573bool parse(input& i, rule& g, error_list& el, void* d, void* ud) { 1574bool 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*/
1609bool 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*/
400bool parse(input& i, rule& g, error_list& el, void* d, void* ud); 401bool 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*/
413bool 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)
880AST_END(Statement, "statement"sv) 879AST_END(Statement, "statement"sv)
881 880
882AST_NODE(Body) 881AST_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
75const std::string_view version = "0.17.0"sv; 75const std::string_view version = "0.17.1"sv;
76const std::string_view extension = "yue"sv; 76const std::string_view extension = "yue"sv;
77 77
78class CompileError : public std::logic_error { 78class 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
902bool 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
908ParseInfo YueParser::parse(std::string_view codes, rule& r) { 928ParseInfo 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
90protected: 95protected:
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)