From 514b9f97febe8920a78d6078b092fe84b859a963 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Thu, 7 Dec 2023 23:49:48 +0800 Subject: changed the if-assignment syntax to prevent some errors. --- doc/docs/doc/README.md | 22 +++++++++++----------- doc/docs/zh/doc/README.md | 22 +++++++++++----------- spec/inputs/assign.yue | 2 +- spec/inputs/compile_doc.yue | 4 ++-- spec/inputs/cond.yue | 28 ++++++++++++++-------------- spec/inputs/destructure.yue | 8 ++++---- spec/inputs/existential.yue | 2 +- spec/inputs/macro_teal.yue | 2 +- spec/inputs/pipe.yue | 2 +- spec/inputs/plus.yue | 8 ++++---- spec/inputs/try_catch.yue | 4 ++-- spec/inputs/unicode/assign.yue | 2 +- spec/inputs/unicode/cond.yue | 28 ++++++++++++++-------------- spec/inputs/unicode/destructure.yue | 8 ++++---- spec/inputs/unicode/existential.yue | 2 +- spec/inputs/unicode/pipe.yue | 2 +- spec/inputs/unicode/plus.yue | 8 ++++---- spec/inputs/unicode/try_catch.yue | 4 ++-- src/yuescript/yue_ast.h | 7 ++++--- src/yuescript/yue_compiler.cpp | 23 +++++++++++++---------- src/yuescript/yue_parser.cpp | 9 +++++++-- src/yuescript/yue_parser.h | 1 + 22 files changed, 104 insertions(+), 94 deletions(-) diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index 54c6b72..041120b 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md @@ -1225,32 +1225,32 @@ We know each element in the array table is a two item tuple, so we can unpack it ## If Assignment -if and elseif blocks can take an assignment in place of a conditional expression. Upon evaluating the conditional, the assignment will take place and the value that was assigned to will be used as the conditional expression. The assigned variable is only in scope for the body of the conditional, meaning it is never available if the value is not truthy. +`if` and `elseif` blocks can take an assignment in place of a conditional expression. Upon evaluating the conditional, the assignment will take place and the value that was assigned to will be used as the conditional expression. The assigned variable is only in scope for the body of the conditional, meaning it is never available if the value is not truthy. And you have to use "the walrus operator" `:=` instead of `=` to do assignment. ```moonscript -if user = database.find_user "moon" +if user := database.find_user "moon" print user.name ```
-if user = database.find_user "moon"
+if user := database.find_user "moon"
   print user.name
 
```moonscript -if hello = os.getenv "hello" +if hello := os.getenv "hello" print "You have hello", hello -elseif world = os.getenv "world" +elseif world := os.getenv "world" print "you have world", world else print "nothing :(" ```
-if hello = os.getenv "hello"
+if hello := os.getenv "hello"
   print "You have hello", hello
-elseif world = os.getenv "world"
+elseif world := os.getenv "world"
   print "you have world", world
 else
   print "nothing :("
@@ -1259,13 +1259,13 @@ else
 
 If assignment with multiple return values. Only the first value is getting checked, other values are scoped.
 ```moonscript
-if success, result = pcall -> "get result without problems"
+if success, result := pcall -> "get result without problems"
   print result -- variable result is scoped
 print "OK"
 ```
 
 
-if success, result = pcall -> "get result without problems"
+if success, result := pcall -> "get result without problems"
   print result -- variable result is scoped
 print "OK"
 
@@ -1374,7 +1374,7 @@ try func 1, 2, 3 -- working with if assignment pattern -if success, result = try func 1, 2, 3 +if success, result := try func 1, 2, 3 catch err print yue.traceback err print result @@ -1402,7 +1402,7 @@ try func 1, 2, 3 -- working with if assignment pattern -if success, result = try func 1, 2, 3 +if success, result := try func 1, 2, 3 catch err print yue.traceback err print result diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md index 7e17b80..a856e7b 100755 --- a/doc/docs/zh/doc/README.md +++ b/doc/docs/zh/doc/README.md @@ -1223,32 +1223,32 @@ for [left, right] in *tuples ## If 赋值 -`if` 和 `elseif` 代码块可以在条件表达式的位置进行赋值。在代码执行到要计算条件时,会首先进行赋值计算,并使用赋与的值作为分支判断的条件。赋值的变量仅在条件分支的代码块内有效,这意味着如果值不是真值,那么它就不会被用到。 +`if` 和 `elseif` 代码块可以在条件表达式的位置进行赋值。在代码执行到要计算条件时,会首先进行赋值计算,并使用赋与的值作为分支判断的条件。赋值的变量仅在条件分支的代码块内有效,这意味着如果值不是真值,那么它就不会被用到。注意,你必须使用“海象运算符” `:=` 而不是 `=` 来做赋值。 ```moonscript -if user = database.find_user "moon" +if user := database.find_user "moon" print user.name ```
-if user = database.find_user "moon"
+if user := database.find_user "moon"
   print user.name
 
```moonscript -if hello = os.getenv "hello" +if hello := os.getenv "hello" print "你有 hello", hello -elseif world = os.getenv "world" +elseif world := os.getenv "world" print "你有 world", world else print "什么都没有 :(" ```
-if hello = os.getenv "hello"
+if hello := os.getenv "hello"
   print "你有 hello", hello
-elseif world = os.getenv "world"
+elseif world := os.getenv "world"
   print "你有 world", world
 else
   print "什么都没有 :("
@@ -1257,13 +1257,13 @@ else
 
 使用多个返回值的 If 赋值。只有第一个值会被检查,其他值都有同样的作用域。
 ```moonscript
-if success, result = pcall -> "无报错地获取结果"
+if success, result := pcall -> "无报错地获取结果"
   print result -- 变量 result 是有作用域的
 print "好的"
 ```
 
 
-if success, result = pcall -> "无报错地获取结果"
+if success, result := pcall -> "无报错地获取结果"
   print result -- 变量 result 是有作用域的
 print "好的"
 
@@ -1372,7 +1372,7 @@ try func 1, 2, 3 -- 使用if赋值模式 -if success, result = try func 1, 2, 3 +if success, result := try func 1, 2, 3 catch err print yue.traceback err print result @@ -1400,7 +1400,7 @@ try func 1, 2, 3 -- 使用if赋值模式 -if success, result = try func 1, 2, 3 +if success, result := try func 1, 2, 3 catch err print yue.traceback err print result diff --git a/spec/inputs/assign.yue b/spec/inputs/assign.yue index 8ae5cac..2c89a99 100644 --- a/spec/inputs/assign.yue +++ b/spec/inputs/assign.yue @@ -30,7 +30,7 @@ c, d = 1, 2 if true x = (do f! - 123) if f = getHandler! + 123) if f := getHandler! (using nil) <- _ diff --git a/spec/inputs/compile_doc.yue b/spec/inputs/compile_doc.yue index 4ce2b13..64d7d40 100644 --- a/spec/inputs/compile_doc.yue +++ b/spec/inputs/compile_doc.yue @@ -8,13 +8,13 @@ for [compiledFile, docFile] in *[ text = \read "*a" codes = [] for code in text\gmatch "```moonscript(.-)```" - if result, err = to_lua code, implicit_return_root: false, reserve_line_number: false + if result, err := to_lua code, implicit_return_root: false, reserve_line_number: false codes[] = result elseif not err\match "macro exporting module only accepts macro definition" print err os.exit 1 for code in text\gmatch "
(.-)
" - if result, err = to_lua code\gsub("<", "<")\gsub(">", ">"), implicit_return_root: false, reserve_line_number: false + if result, err := to_lua code\gsub("<", "<")\gsub(">", ">"), implicit_return_root: false, reserve_line_number: false codes[] = result else print err diff --git a/spec/inputs/cond.yue b/spec/inputs/cond.yue index 5bc6c9b..cce96df 100644 --- a/spec/inputs/cond.yue +++ b/spec/inputs/cond.yue @@ -52,18 +52,18 @@ elseif "just us" -- -if something = 10 +if something := 10 print something else print "else" -hello = if something = 10 +hello = if something := 10 print something else print "else" -hello = 5 + if something = 10 +hello = 5 + if something := 10 print something --- @@ -72,9 +72,9 @@ z = false _ = if false one -elseif x = true +elseif x := true two -elseif z = true +elseif z := true three else four @@ -82,17 +82,17 @@ else out = if false one -elseif x = true +elseif x := true two -elseif z = true +elseif z := true three else four kzy = -> - if something = true + if something := true 1 - elseif another = false + elseif another := false 2 --- @@ -152,7 +152,7 @@ dddd = {1,2,3} unless value do j = 100 - unless j = hi! + unless j := hi! error "not j!" ---------------- @@ -200,22 +200,22 @@ do elseif c d: e = tb -if :pi = math +if :pi := math print pi do local math - if :pi = math + if :pi := math print pi do - if _M = {} + if _M := {} :Thing = _M :a, :b = _M do global _M - if _M = {} + if _M := {} :Thing = _M :a, :b = _M diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue index 73e4d33..5017ee1 100644 --- a/spec/inputs/destructure.yue +++ b/spec/inputs/destructure.yue @@ -94,18 +94,18 @@ do do thing = nil - if {a} = thing + if {a} := thing print a else print "nothing" thang = {1,2} - if {a,b} = thang + if {a,b} := thang print a,b - if {a,b} = thing + if {a,b} := thing print a,b - elseif {c,d} = thang + elseif {c,d} := thang print c,d else print "NO" diff --git a/spec/inputs/existential.yue b/spec/inputs/existential.yue index 27891dc..ec38897 100644 --- a/spec/inputs/existential.yue +++ b/spec/inputs/existential.yue @@ -16,7 +16,7 @@ with abc?!\func?! if \p? "abc" return 123 -if {:x} = a?.if?\then?(123)? @?\function 998 +if {:x} := a?.if?\then?(123)? @?\function 998 print x res = b.function\do!\while?("OK")\if("def",998)\f? diff --git a/spec/inputs/macro_teal.yue b/spec/inputs/macro_teal.yue index a443614..0cfd862 100644 --- a/spec/inputs/macro_teal.yue +++ b/spec/inputs/macro_teal.yue @@ -8,7 +8,7 @@ macro to_lua = (code)-> "require('yue').to_lua(#{code}, reserve_line_number:false, same_module:true)" macro trim = (name)-> - "if result = #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" + "if result := #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" export macro local = (decl, value = nil)-> import "yue" as {options:{:tl_enabled}} diff --git a/spec/inputs/pipe.yue b/spec/inputs/pipe.yue index 02f87a3..b5bae1d 100644 --- a/spec/inputs/pipe.yue +++ b/spec/inputs/pipe.yue @@ -11,7 +11,7 @@ b = 1 + 2 + (4 |> tostring |> print(1) or 123) -if x = 233 |> math.max 998 +if x := 233 |> math.max 998 print x with b |> create? "new" diff --git a/spec/inputs/plus.yue b/spec/inputs/plus.yue index e387090..9c500a4 100644 --- a/spec/inputs/plus.yue +++ b/spec/inputs/plus.yue @@ -8,13 +8,13 @@ c.repeat.if\then("xyz")\else res print @for,@@function 123 -if fcolor = message\match "<%w*>" then message = message\gsub "<%->", fcolor +if fcolor := message\match "<%w*>" then message = message\gsub "<%->", fcolor -message = message\gsub "<%->", fcolor if fcolor = message\match "<%w*>" +message = message\gsub "<%->", fcolor if fcolor := message\match "<%w*>" -valA = func! if func = getfunc! +valA = func! if func := getfunc! -local valA = func! if func = getfunc! +local valA = func! if func := getfunc! valB = do func = getfunc! diff --git a/spec/inputs/try_catch.yue b/spec/inputs/try_catch.yue index 96a87fc..ccb3f52 100644 --- a/spec/inputs/try_catch.yue +++ b/spec/inputs/try_catch.yue @@ -39,14 +39,14 @@ catch err print "OK" do - if success, result = try func "abc", 123 + if success, result := try func "abc", 123 print result success, result = try func "abc", 123 catch err print err - print result if success, result = try func "abc", 123 + print result if success, result := try func "abc", 123 catch err print err diff --git a/spec/inputs/unicode/assign.yue b/spec/inputs/unicode/assign.yue index 5392a92..6c03f86 100644 --- a/spec/inputs/unicode/assign.yue +++ b/spec/inputs/unicode/assign.yue @@ -30,7 +30,7 @@ else 变量x = (do 函数! - 123) if 函数 = 获取处理函数! + 123) if 函数 := 获取处理函数! (using nil) <- _无效变量 diff --git a/spec/inputs/unicode/cond.yue b/spec/inputs/unicode/cond.yue index fca6d60..dde5c99 100644 --- a/spec/inputs/unicode/cond.yue +++ b/spec/inputs/unicode/cond.yue @@ -52,18 +52,18 @@ elseif "只有我们" -- -if 某东西 = 10 +if 某东西 := 10 打印 某东西 else 打印 "其它" -你好 = if 某东西 = 10 +你好 = if 某东西 := 10 打印 某东西 else 打印 "其它" -你好 = 5 + if 某东西 = 10 +你好 = 5 + if 某东西 := 10 打印 某东西 --- @@ -72,9 +72,9 @@ z变量 = false _无效变量 = if false 一 -elseif 条件x = true +elseif 条件x := true 二 -elseif 条件z = true +elseif 条件z := true 三 else 四 @@ -82,17 +82,17 @@ else 输出 = if false 一 -elseif 条件x = true +elseif 条件x := true 二 -elseif 条件z = true +elseif 条件z := true 三 else 四 变量 = -> - if 某东西 = true + if 某东西 := true 1 - elseif 另一个 = false + elseif 另一个 := false 2 --- @@ -152,7 +152,7 @@ else do j变量 = 100 - unless j变量 = 嗨! + unless j变量 := 嗨! 错误 "不是 j变量!" ---------------- @@ -200,22 +200,22 @@ do elseif 条件c 字段d: 变量e = 变量tb -if :派 = 数学库 +if :派 := 数学库 打印 派 do local 数学库 - if :派 = 数学库 + if :派 := 数学库 打印 派 do - if _模块 = {} + if _模块 := {} :东西 = _模块 :a功能, :b功能 = _模块 do global _模块 - if _模块 = {} + if _模块 := {} :东西 = _模块 :a功能, :b功能 = _模块 diff --git a/spec/inputs/unicode/destructure.yue b/spec/inputs/unicode/destructure.yue index 5efdf82..3c3a369 100644 --- a/spec/inputs/unicode/destructure.yue +++ b/spec/inputs/unicode/destructure.yue @@ -92,18 +92,18 @@ do do 东西 = nil - if {元素a} = 东西 + if {元素a} := 东西 打印 元素a else 打印 "没东西" 东东 = {1,2} - if {元素a,元素b} = 东东 + if {元素a,元素b} := 东东 打印 元素a,元素b - if {元素a,元素b} = 东西 + if {元素a,元素b} := 东西 打印 元素a,元素b - elseif {元素c,元素d} = 东东 + elseif {元素c,元素d} := 东东 打印 元素c,元素d else 打印 "不" diff --git a/spec/inputs/unicode/existential.yue b/spec/inputs/unicode/existential.yue index 0e35a39..de65027 100644 --- a/spec/inputs/unicode/existential.yue +++ b/spec/inputs/unicode/existential.yue @@ -16,7 +16,7 @@ with 对象abc?!\函数?! if \函数p? "abc" return 123 -if {:x字段} = 对象a?.如果?\然后?(123)? @?\方法 998 +if {:x字段} := 对象a?.如果?\然后?(123)? @?\方法 998 打印 x字段 结果 = 对象b.方法\执行!\当?("没问题")\如果("默认",998)\函数? diff --git a/spec/inputs/unicode/pipe.yue b/spec/inputs/unicode/pipe.yue index 2cd41ee..085a2cf 100644 --- a/spec/inputs/unicode/pipe.yue +++ b/spec/inputs/unicode/pipe.yue @@ -11,7 +11,7 @@ 变量b = 1 + 2 + (4 |> tostring |> 打印(1) or 123) -if 变量x = 233 |> math.max 998 +if 变量x := 233 |> math.max 998 打印 变量x with 变量b |> 创建? "new" diff --git a/spec/inputs/unicode/plus.yue b/spec/inputs/unicode/plus.yue index b08974f..70b57bb 100644 --- a/spec/inputs/unicode/plus.yue +++ b/spec/inputs/unicode/plus.yue @@ -8,13 +8,13 @@ 打印 @循环, @@函数 123 -if 颜色 = 消息\匹配 "<%w*>" then 消息 = 消息\替换 "<%->", 颜色 +if 颜色 := 消息\匹配 "<%w*>" then 消息 = 消息\替换 "<%->", 颜色 -消息 = 消息\替换 "<%->", 颜色 if 颜色 = 消息\匹配 "<%w*>" +消息 = 消息\替换 "<%->", 颜色 if 颜色 := 消息\匹配 "<%w*>" -数值A = 方法! if 方法 = 获取方法! +数值A = 方法! if 方法 := 获取方法! -local 数值A = 方法! if 方法 = 获取方法! +local 数值A = 方法! if 方法 := 获取方法! 数值B = do 方法 = 获取方法! diff --git a/spec/inputs/unicode/try_catch.yue b/spec/inputs/unicode/try_catch.yue index 71e03ee..1156d8e 100644 --- a/spec/inputs/unicode/try_catch.yue +++ b/spec/inputs/unicode/try_catch.yue @@ -39,14 +39,14 @@ catch 错误 打印 "好的" do - if 成功, 结果 = try 函数 "abc", 123 + if 成功, 结果 := try 函数 "abc", 123 打印 结果 成功, 结果 = try 函数 "abc", 123 catch 错误 打印 错误 - 打印 结果 if 成功, 结果 = try 函数 "abc", 123 + 打印 结果 if 成功, 结果 := try 函数 "abc", 123 catch 错误 打印 错误 diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index fa47559..6b2b7f8 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -302,14 +302,15 @@ AST_NODE(Switch) AST_END(Switch, "switch"sv) AST_NODE(Assignment) - ast_ptr expList; + ast_ptr expList; ast_ptr assign; AST_MEMBER(Assignment, &expList, &assign) AST_END(Assignment, "assignment"sv) AST_NODE(IfCond) - ast_sel condition; - AST_MEMBER(IfCond, &condition) + ast_ptr condition; + ast_ptr assignment; + AST_MEMBER(IfCond, &condition, &assignment) AST_END(IfCond, "if_cond"sv) AST_LEAF(IfType) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 69a028f..d37f911 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -75,7 +75,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.20.7"sv; +const std::string_view version = "0.21.0"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -3088,7 +3088,7 @@ private: for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) { ns.push_back(*it); if (auto cond = ast_cast(*it)) { - if (*it != nodes.front() && cond->condition.is()) { + if (*it != nodes.front() && cond->assignment) { auto x = *it; auto newIf = x->new_ptr(); newIf->type.set(toAst("if"sv, x)); @@ -3142,11 +3142,12 @@ private: default: YUEE("AST node mismatch", node); break; } } - auto asmt = ifCondPairs.front().first->condition.as(); + auto firstIfCond = ifCondPairs.front().first; + auto asmt = firstIfCond->assignment.get(); bool storingValue = false; ast_ptr extraAssignment; if (asmt) { - ast_ptr exp = asmt->expList->exprs.front(); + auto exp = firstIfCond->condition.get(); auto x = exp; auto var = singleVariableFrom(exp, false); if (var.empty() || isGlobal(var)) { @@ -3164,11 +3165,12 @@ private: temp.push_back(indent() + "do"s + nll(asmt)); pushScope(); } - asmt->expList->exprs.pop_front(); auto expList = toAst(desVar, x); auto assignment = x->new_ptr(); - for (auto expr : asmt->expList->exprs.objects()) { - expList->exprs.push_back(expr); + if (asmt->expList) { + for (auto expr : asmt->expList->exprs.objects()) { + expList->exprs.push_back(expr); + } } assignment->expList.set(expList); assignment->action.set(asmt->assign); @@ -3196,9 +3198,10 @@ private: } auto expList = x->new_ptr(); expList->exprs.push_back(exp); - asmt->expList->exprs.pop_front(); - for (auto expr : asmt->expList->exprs.objects()) { - expList->exprs.push_back(expr); + if (asmt->expList) { + for (auto expr : asmt->expList->exprs.objects()) { + expList->exprs.push_back(expr); + } } auto assignment = x->new_ptr(); assignment->expList.set(expList); diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 2206686..5b97a25 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -114,6 +114,11 @@ 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); + return false; + }); + #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut) #define key(str) (expr(str) >> not_alpha_num) @@ -369,8 +374,8 @@ YueParser::YueParser() { +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent ) >> switch_block; - Assignment = ExpList >> space >> Assign; - IfCond = disable_chain_rule(disable_arg_table_block_rule(Assignment | Exp)); + Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_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; IfType = (expr("if") | "unless") >> not_alpha_num; diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 16b57b2..c3d5d7d 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -141,6 +141,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(inc_exp_level); NONE_AST_RULE(dec_exp_level); -- cgit v1.2.3-55-g6feb