From a91135ce512f907ed085d9aac147d8fcad356406 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 26 May 2025 11:07:38 +0800 Subject: Added assignment expression for switch syntax. --- doc/docs/doc/README.md | 16 ++++---- doc/docs/zh/doc/README.md | 16 ++++---- spec/inputs/destructure.yue | 2 +- spec/inputs/macro_export.yue | 4 +- spec/inputs/switch.yue | 54 ++++++++++++++++++++++++++- spec/inputs/unicode/destructure.yue | 2 +- spec/inputs/unicode/macro_export.yue | 4 +- spec/inputs/unicode/with.yue | 24 ++++++------ spec/inputs/with.yue | 24 ++++++------ spec/outputs/codes_from_doc.lua | 4 +- spec/outputs/codes_from_doc_zh.lua | 4 +- spec/outputs/switch.lua | 71 ++++++++++++++++++++++++++++++++++++ src/yuescript/yue_ast.cpp | 7 +++- src/yuescript/yue_ast.h | 19 +++++----- src/yuescript/yue_compiler.cpp | 32 ++++++++++++---- src/yuescript/yue_parser.cpp | 11 +++--- src/yuescript/yue_parser.h | 2 +- 17 files changed, 218 insertions(+), 78 deletions(-) diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index 58b37c0..7e9b454 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md @@ -2696,28 +2696,26 @@ reader\parse_line! until reader\eof! ## Switch -The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. +The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. In switch statement, you can also use assignment expression to store temporary variable value. ```moonscript -name = "Dan" -switch name +switch name := "Dan" when "Robert" print "You are Robert" when "Dan", "Daniel" print "Your name, it's Dan" else - print "I don't know about your name" + print "I don't know about you with name #{name}" ```
-name = "Dan"
-switch name
+switch name := "Dan"
   when "Robert"
     print "You are Robert"
   when "Dan", "Daniel"
     print "Your name, it's Dan"
   else
-    print "I don't know about your name"
+    print "I don't know about you with name #{name}"
 
@@ -3528,13 +3526,13 @@ In this usage, with can be seen as a special form of the K combinator. The expression in the with statement can also be an assignment, if you want to give a name to the expression. ```moonscript -with str = "Hello" +with str := "Hello" print "original:", str print "upper:", \upper! ```
-with str = "Hello"
+with str := "Hello"
   print "original:", str
   print "upper:", \upper!
 
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md index 1dd59a7..da90fa6 100755 --- a/doc/docs/zh/doc/README.md +++ b/doc/docs/zh/doc/README.md @@ -2655,28 +2655,26 @@ reader\parse_line! until reader\eof! ## switch 语句 -switch语句是为了简化检查一系列相同值的if语句而提供的简写语法。要注意用于比较检查的目标值只会计算一次。和if语句一样,switch语句在最后可以接一个else代码块来处理没有匹配的情况。在生成的Lua代码中,进行比较是使用==操作符完成的。 +switch语句是为了简化检查一系列相同值的if语句而提供的简写语法。要注意用于比较检查的目标值只会计算一次。和if语句一样,switch语句在最后可以接一个else代码块来处理没有匹配的情况。在生成的Lua代码中,进行比较是使用==操作符完成的。switch语句中也可以使用赋值表达式来储存临时变量值。 ```moonscript -name = "Dan" -switch name +switch name := "Dan" when "Robert" print "你是Robert" when "Dan", "Daniel" print "你的名字是Dan" else - print "我不知道你的名字" + print "我不认识你,你的名字是#{name}" ```
-name = "Dan"
-switch name
+switch name := "Dan"
   when "Robert"
     print "你是Robert"
   when "Dan", "Daniel"
     print "你的名字是Dan"
   else
-    print "我不知道你的名字"
+    print "我不认识你,你的名字是#{name}"
 
@@ -3484,13 +3482,13 @@ me = create_person "Leaf", [dad, mother, sister] 如果你想给表达式另外起一个名称的话,with语句中的表达式也可以是一个赋值语句。 ```moonscript -with str = "你好" +with str := "你好" print "原始:", str print "大写:", \upper! ```
-with str = "你好"
+with str := "你好"
   print "原始:", str
   print "大写:", \upper!
 
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue index 674dfe4..9f01a20 100644 --- a/spec/inputs/destructure.yue +++ b/spec/inputs/destructure.yue @@ -94,7 +94,7 @@ do -- do - with {a,b} = thing + with {a,b} := thing print a, b diff --git a/spec/inputs/macro_export.yue b/spec/inputs/macro_export.yue index cc7d459..75fd813 100644 --- a/spec/inputs/macro_export.yue +++ b/spec/inputs/macro_export.yue @@ -38,8 +38,8 @@ export macro copy = (src, dst, ...)-> " do local _src_, _dst_ - with _dst_ = #{dst} - with _src_ = #{src} + with _dst_ := #{dst} + with _src_ := #{src} #{table.concat for field in *{...} do " _dst_.#{field} = _src_.#{field} "}" diff --git a/spec/inputs/switch.yue b/spec/inputs/switch.yue index 7ff3118..5097db3 100644 --- a/spec/inputs/switch.yue +++ b/spec/inputs/switch.yue @@ -220,4 +220,56 @@ do ] print "matched", sixth -nil \ No newline at end of file +do + switch v := "hello" + when "hello" + print "matched hello" + else + print "not matched" + -- output: matched hello + +do + f = -> "ok" + switch val := f! + when "ok" + print "it's ok" + -- output: it's ok + + +do + g = -> 42 + switch result := g! + when 1, 2 + print "small" + when 42 + print "life universe everything" + else + print "other #{result}" + -- output: life universe everything + +do + check = -> + if true + "yes" + else + "no" + + switch x := check! + when "yes" + print "affirmative" + else + print "negative" + -- output: affirmative + +do + t = (): tb -> + tb = {a: 1} + tb.a = 2 + + switch data := t! + when {a: 2} + print "matched" + else + print "not matched" + +nil diff --git a/spec/inputs/unicode/destructure.yue b/spec/inputs/unicode/destructure.yue index 3c3a369..a5ffd5d 100644 --- a/spec/inputs/unicode/destructure.yue +++ b/spec/inputs/unicode/destructure.yue @@ -84,7 +84,7 @@ do -- do - with {元素a,元素b} = 东西 + with {元素a,元素b} := 东西 打印 元素a, 元素b diff --git a/spec/inputs/unicode/macro_export.yue b/spec/inputs/unicode/macro_export.yue index 3c9a942..56571cd 100644 --- a/spec/inputs/unicode/macro_export.yue +++ b/spec/inputs/unicode/macro_export.yue @@ -37,8 +37,8 @@ export macro 复制 = (源, 目标, ...)-> " do local _源_, _目标_ - with _目标_ = #{目标} - with _源_ = #{源} + with _目标_ := #{目标} + with _源_ := #{源} #{table.concat for 字段 in *{...} do " _目标_.#{字段} = _源_.#{字段} "}" diff --git a/spec/inputs/unicode/with.yue b/spec/inputs/unicode/with.yue index ecbfdab..3c15add 100644 --- a/spec/inputs/unicode/with.yue +++ b/spec/inputs/unicode/with.yue @@ -45,19 +45,19 @@ do with 变量a 打印 .世界 - 模块 = with _模块 = {} + 模块 = with _模块 := {} .事物 = "你好" - with 变量a, 变量b = 东西, 布 + with 变量a, 变量b := 东西, 布 打印 .世界 - 变量x = with 变量a, 变量b = 1, 2 + 变量x = with 变量a, 变量b := 1, 2 打印 变量a + 变量b - 打印 with 变量a, 变量b = 1, 2 + 打印 with 变量a, 变量b := 1, 2 打印 变量a + 变量b - p = with 你好!.字段x, 世界!.字段y = 1, 2 + p = with 你好!.字段x, 世界!.字段y := 1, 2 打印 变量a + 变量b -- @@ -68,16 +68,16 @@ do 变量x\大写! do - with 变量k = "乔" + with 变量k := "乔" 打印 \大写! do - with 变量a,变量b,变量c = "", "", "" + with 变量a,变量b,变量c := "", "", "" 打印 \大写! do 变量a = "床铺" - with 变量a,变量b,变量c = "", "", "" + with 变量a,变量b,变量c := "", "", "" 打印 \大写! do @@ -85,7 +85,7 @@ do 打印 \大写! do - with 变量k.变量j = "乔" + with 变量k.变量j := "乔" 打印 \大写! do @@ -96,7 +96,7 @@ do do with 变量a - with .b = 2 + with .b := 2 打印 .c do @@ -131,12 +131,12 @@ do do global 掩码 - with? 掩码 = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 + with? 掩码 := 实心矩形 宽: w, 高: h, 颜色: 0x66000000 .触摸启用 = true .吞噬触摸 = true do - with? 掩码 = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 + with? 掩码 := 实心矩形 宽: w, 高: h, 颜色: 0x66000000 .触摸启用 = true .吞噬触摸 = true diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue index dcd4053..c1cf3e3 100644 --- a/spec/inputs/with.yue +++ b/spec/inputs/with.yue @@ -48,21 +48,21 @@ do with a -- only one value allowed print .world - mod = with _M = {} + mod = with _M := {} .Thing = "hi" -- operate on a only - with a, b = something, pooh + with a, b := something, pooh print .world - x = with a, b = 1, 2 + x = with a, b := 1, 2 print a + b - print with a, b = 1, 2 + print with a, b := 1, 2 print a + b -- assignment lhs must be evaluated in the order they appear - p = with hello!.x, world!.y = 1, 2 + p = with hello!.x, world!.y := 1, 2 print a + b -- @@ -73,16 +73,16 @@ do x\upper! do - with k = "jo" + with k := "jo" print \upper! do - with a,b,c = "", "", "" + with a,b,c := "", "", "" print \upper! do a = "bunk" - with a,b,c = "", "", "" + with a,b,c := "", "", "" print \upper! do @@ -90,7 +90,7 @@ do print \upper! do - with k.j = "jo" + with k.j := "jo" print \upper! do @@ -103,7 +103,7 @@ do do with a -- nested `with`s with assignments should change the scope correctly - with .b = 2 + with .b := 2 print .c do @@ -138,12 +138,12 @@ do do global mask - with? mask = SolidRect width: w, height: h, color: 0x66000000 + with? mask := SolidRect width: w, height: h, color: 0x66000000 .touchEnabled = true .swallowTouches = true do - with? mask = SolidRect width: w, height: h, color: 0x66000000 + with? mask := SolidRect width: w, height: h, color: 0x66000000 .touchEnabled = true .swallowTouches = true diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua index c7a2d50..d857dec 100644 --- a/spec/outputs/codes_from_doc.lua +++ b/spec/outputs/codes_from_doc.lua @@ -1234,7 +1234,7 @@ if "Robert" == name then elseif "Dan" == name or "Daniel" == name then print("Your name, it's Dan") else - print("I don't know about your name") + print("I don't know about you with name " .. tostring(name)) end local b = 1 local next_number @@ -3450,7 +3450,7 @@ if "Robert" == name then elseif "Dan" == name or "Daniel" == name then print("Your name, it's Dan") else - print("I don't know about your name") + print("I don't know about you with name " .. tostring(name)) end local b = 1 local next_number diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua index fcde41f..ecab077 100644 --- a/spec/outputs/codes_from_doc_zh.lua +++ b/spec/outputs/codes_from_doc_zh.lua @@ -1228,7 +1228,7 @@ if "Robert" == name then elseif "Dan" == name or "Daniel" == name then print("你的名字是Dan") else - print("我不知道你的名字") + print("我不认识你,你的名字是" .. tostring(name)) end local b = 1 local next_number @@ -3438,7 +3438,7 @@ if "Robert" == name then elseif "Dan" == name or "Daniel" == name then print("你的名字是Dan") else - print("我不知道你的名字") + print("我不认识你,你的名字是" .. tostring(name)) end local b = 1 local next_number diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua index 0f8bba2..204b816 100644 --- a/spec/outputs/switch.lua +++ b/spec/outputs/switch.lua @@ -656,4 +656,75 @@ do end end end +do + local v = "hello" + if "hello" == v then + print("matched hello") + else + print("not matched") + end +end +do + local f + f = function() + return "ok" + end + local val = f() + if "ok" == val then + print("it's ok") + end +end +do + local g + g = function() + return 42 + end + local result = g() + if 1 == result or 2 == result then + print("small") + elseif 42 == result then + print("life universe everything") + else + print("other " .. tostring(result)) + end +end +do + local check + check = function() + if true then + return "yes" + else + return "no" + end + end + local x = check() + if "yes" == x then + print("affirmative") + else + print("negative") + end +end +do + local t + t = function() + local tb = { + a = 1 + } + tb.a = 2 + return tb + end + local data = t() + local _type_0 = type(data) + local _tab_0 = "table" == _type_0 or "userdata" == _type_0 + local _match_0 = false + if _tab_0 then + if 2 == data.a then + _match_0 = true + print("matched") + end + end + if not _match_0 then + print("not matched") + end +end return nil diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index fdb1d20..e69dd37 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp @@ -372,8 +372,8 @@ std::string With_t::to_string(void* ud) const { str_list temp{ eop ? "with?"s : "with"s, valueList->to_string(ud)}; - if (assigns) { - temp.push_back(assigns->to_string(ud)); + if (assign) { + temp.push_back(':' + assign->to_string(ud)); } if (body.is()) { return join(temp, " "sv) + " do "s + body->to_string(ud); @@ -419,6 +419,9 @@ std::string SwitchCase_t::to_string(void* ud) const { std::string Switch_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); str_list temp{"switch "s + target->to_string(ud)}; + if (assignment) { + temp.back().append(" :"s + assignment->to_string(ud)); + } info->pushScope(); for (auto branch : branches.objects()) { temp.emplace_back(info->ind() + branch->to_string(ud)); diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 0c15fac..946a587 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -287,9 +287,9 @@ AST_END(Return) AST_NODE(With) ast_ptr eop; ast_ptr valueList; - ast_ptr assigns; + ast_ptr assign; ast_sel body; - AST_MEMBER(With, &eop, &valueList, &assigns, &body) + AST_MEMBER(With, &eop, &valueList, &assign, &body) AST_END(With) AST_NODE(SwitchList) @@ -304,20 +304,21 @@ AST_NODE(SwitchCase) AST_MEMBER(SwitchCase, &condition, &body) AST_END(SwitchCase) +AST_NODE(Assignment) + ast_ptr expList; + ast_ptr assign; + AST_MEMBER(Assignment, &expList, &assign) +AST_END(Assignment) + AST_NODE(Switch) ast_ptr target; + ast_ptr assignment; ast_ptr sep; ast_list branches; ast_sel lastBranch; - AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) + AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch) AST_END(Switch) -AST_NODE(Assignment) - ast_ptr expList; - ast_ptr assign; - AST_MEMBER(Assignment, &expList, &assign) -AST_END(Assignment) - AST_NODE(IfCond) ast_ptr condition; ast_ptr assignment; diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 7abc929..9d2037f 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -78,7 +78,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.28.3"sv; +const std::string_view version = "0.28.4"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -9370,11 +9370,11 @@ private: std::string withVar; bool needScope = !currentScope().lastStatement && !returnValue; bool extraScope = false; - if (with->assigns) { + if (with->assign) { auto vars = getAssignVars(with); if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { - if (with->assigns->values.objects().size() == 1) { - auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); + if (with->assign->values.objects().size() == 1) { + auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read); if (!var.empty() && isLocal(var)) { withVar = var; } @@ -9384,7 +9384,7 @@ private: auto assignment = x->new_ptr(); assignment->expList.set(toAst(withVar, x)); auto assign = x->new_ptr(); - assign->values.push_back(with->assigns->values.objects().front()); + assign->values.push_back(with->assign->values.objects().front()); assignment->action.set(assign); if (needScope) { extraScope = true; @@ -9398,7 +9398,7 @@ private: auto assign = x->new_ptr(); assign->values.push_back(toAst(withVar, x)); bool skipFirst = true; - for (auto value : with->assigns->values.objects()) { + for (auto value : with->assign->values.objects()) { if (skipFirst) { skipFirst = false; continue; @@ -9411,7 +9411,7 @@ private: withVar = vars.front(); auto assignment = x->new_ptr(); assignment->expList.set(with->valueList); - assignment->action.set(with->assigns); + assignment->action.set(with->assign); if (needScope) { extraScope = true; temp.push_back(indent() + "do"s + nll(with)); @@ -10760,10 +10760,26 @@ private: pushScope(); } bool extraScope = false; + if (switchNode->assignment) { + if (needScope) { + extraScope = true; + temp.push_back(indent() + "do"s + nll(x)); + pushScope(); + } + auto asmt = x->new_ptr(); + auto expList = x->new_ptr(); + expList->exprs.push_back(switchNode->target); + if (switchNode->assignment->expList) { + expList->exprs.dup(switchNode->assignment->expList->exprs); + } + asmt->expList.set(expList); + asmt->action.set(switchNode->assignment->assign); + transformAssignment(asmt, temp); + } auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); if (objVar.empty() || !isLocal(objVar)) { if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { - if (needScope) { + if (needScope && !extraScope) { extraScope = true; temp.push_back(indent() + "do"s + nll(x)); pushScope(); diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 078509c..0271e07 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -118,8 +118,8 @@ YueParser::YueParser() { return false; }); - if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { - throw ParserError("use := for if-assignment expression"sv, item.begin); + assignment_expression_syntax_error = pl::user(true_(), [](const item_t& item) { + throw ParserError("use := for assignment expression"sv, item.begin); return false; }); @@ -356,7 +356,7 @@ YueParser::YueParser() { Return = key("return") >> -(space >> (TableBlock | ExpListLow)); - with_exp = ExpList >> -(space >> Assign); + with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error)); With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); @@ -372,7 +372,8 @@ YueParser::YueParser() { and_(SimpleTable | TableLit) >> Exp | exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) ); - Switch = key("switch") >> space >> Exp >> + Switch = key("switch") >> space >> + Exp >> -(space >> Assignment) >> space >> Seperator >> ( SwitchCase >> space >> ( switch_block | @@ -381,7 +382,7 @@ YueParser::YueParser() { +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent ); - Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); + Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error); IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 4488685..6263857 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -156,7 +156,7 @@ private: NONE_AST_RULE(invalid_interpolation_error); NONE_AST_RULE(confusing_unary_not_error); NONE_AST_RULE(table_key_pair_error); - NONE_AST_RULE(if_assignment_syntax_error); + NONE_AST_RULE(assignment_expression_syntax_error); NONE_AST_RULE(inc_exp_level); NONE_AST_RULE(dec_exp_level); -- cgit v1.2.3-55-g6feb