aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-05-26 11:07:38 +0800
committerLi Jin <dragon-fly@qq.com>2025-05-26 11:07:38 +0800
commita91135ce512f907ed085d9aac147d8fcad356406 (patch)
treee53408fe0a88ef71ea33d14bcb0b6eeb3a344810
parent4ba4c90e711c6204aa40e38347c5a5a076d9370e (diff)
downloadyuescript-a91135ce512f907ed085d9aac147d8fcad356406.tar.gz
yuescript-a91135ce512f907ed085d9aac147d8fcad356406.tar.bz2
yuescript-a91135ce512f907ed085d9aac147d8fcad356406.zip
Added assignment expression for switch syntax.
-rwxr-xr-xdoc/docs/doc/README.md16
-rwxr-xr-xdoc/docs/zh/doc/README.md16
-rw-r--r--spec/inputs/destructure.yue2
-rw-r--r--spec/inputs/macro_export.yue4
-rw-r--r--spec/inputs/switch.yue54
-rw-r--r--spec/inputs/unicode/destructure.yue2
-rw-r--r--spec/inputs/unicode/macro_export.yue4
-rw-r--r--spec/inputs/unicode/with.yue24
-rw-r--r--spec/inputs/with.yue24
-rw-r--r--spec/outputs/codes_from_doc.lua4
-rw-r--r--spec/outputs/codes_from_doc_zh.lua4
-rw-r--r--spec/outputs/switch.lua71
-rw-r--r--src/yuescript/yue_ast.cpp7
-rw-r--r--src/yuescript/yue_ast.h19
-rw-r--r--src/yuescript/yue_compiler.cpp32
-rw-r--r--src/yuescript/yue_parser.cpp11
-rw-r--r--src/yuescript/yue_parser.h2
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!
2696 2696
2697## Switch 2697## Switch
2698 2698
2699The 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. 2699The 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.
2700 2700
2701```moonscript 2701```moonscript
2702name = "Dan" 2702switch name := "Dan"
2703switch name
2704 when "Robert" 2703 when "Robert"
2705 print "You are Robert" 2704 print "You are Robert"
2706 when "Dan", "Daniel" 2705 when "Dan", "Daniel"
2707 print "Your name, it's Dan" 2706 print "Your name, it's Dan"
2708 else 2707 else
2709 print "I don't know about your name" 2708 print "I don't know about you with name #{name}"
2710``` 2709```
2711<YueDisplay> 2710<YueDisplay>
2712<pre> 2711<pre>
2713name = "Dan" 2712switch name := "Dan"
2714switch name
2715 when "Robert" 2713 when "Robert"
2716 print "You are Robert" 2714 print "You are Robert"
2717 when "Dan", "Daniel" 2715 when "Dan", "Daniel"
2718 print "Your name, it's Dan" 2716 print "Your name, it's Dan"
2719 else 2717 else
2720 print "I don't know about your name" 2718 print "I don't know about you with name #{name}"
2721</pre> 2719</pre>
2722</YueDisplay> 2720</YueDisplay>
2723 2721
@@ -3528,13 +3526,13 @@ In this usage, with can be seen as a special form of the K combinator.
3528The expression in the with statement can also be an assignment, if you want to give a name to the expression. 3526The expression in the with statement can also be an assignment, if you want to give a name to the expression.
3529 3527
3530```moonscript 3528```moonscript
3531with str = "Hello" 3529with str := "Hello"
3532 print "original:", str 3530 print "original:", str
3533 print "upper:", \upper! 3531 print "upper:", \upper!
3534``` 3532```
3535<YueDisplay> 3533<YueDisplay>
3536<pre> 3534<pre>
3537with str = "Hello" 3535with str := "Hello"
3538 print "original:", str 3536 print "original:", str
3539 print "upper:", \upper! 3537 print "upper:", \upper!
3540</pre> 3538</pre>
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!
2655 2655
2656## switch 语句 2656## switch 语句
2657 2657
2658switch语句是为了简化检查一系列相同值的if语句而提供的简写语法。要注意用于比较检查的目标值只会计算一次。和if语句一样,switch语句在最后可以接一个else代码块来处理没有匹配的情况。在生成的Lua代码中,进行比较是使用==操作符完成的。 2658switch语句是为了简化检查一系列相同值的if语句而提供的简写语法。要注意用于比较检查的目标值只会计算一次。和if语句一样,switch语句在最后可以接一个else代码块来处理没有匹配的情况。在生成的Lua代码中,进行比较是使用==操作符完成的。switch语句中也可以使用赋值表达式来储存临时变量值。
2659 2659
2660```moonscript 2660```moonscript
2661name = "Dan" 2661switch name := "Dan"
2662switch name
2663 when "Robert" 2662 when "Robert"
2664 print "你是Robert" 2663 print "你是Robert"
2665 when "Dan", "Daniel" 2664 when "Dan", "Daniel"
2666 print "你的名字是Dan" 2665 print "你的名字是Dan"
2667 else 2666 else
2668 print "我不知道你的名字" 2667 print "我不认识,你的名字是#{name}"
2669``` 2668```
2670<YueDisplay> 2669<YueDisplay>
2671<pre> 2670<pre>
2672name = "Dan" 2671switch name := "Dan"
2673switch name
2674 when "Robert" 2672 when "Robert"
2675 print "你是Robert" 2673 print "你是Robert"
2676 when "Dan", "Daniel" 2674 when "Dan", "Daniel"
2677 print "你的名字是Dan" 2675 print "你的名字是Dan"
2678 else 2676 else
2679 print "我不知道你的名字" 2677 print "我不认识,你的名字是#{name}"
2680</pre> 2678</pre>
2681</YueDisplay> 2679</YueDisplay>
2682 2680
@@ -3484,13 +3482,13 @@ me = create_person "Leaf", [dad, mother, sister]
3484如果你想给表达式另外起一个名称的话,with语句中的表达式也可以是一个赋值语句。 3482如果你想给表达式另外起一个名称的话,with语句中的表达式也可以是一个赋值语句。
3485 3483
3486```moonscript 3484```moonscript
3487with str = "你好" 3485with str := "你好"
3488 print "原始:", str 3486 print "原始:", str
3489 print "大写:", \upper! 3487 print "大写:", \upper!
3490``` 3488```
3491<YueDisplay> 3489<YueDisplay>
3492<pre> 3490<pre>
3493with str = "你好" 3491with str := "你好"
3494 print "原始:", str 3492 print "原始:", str
3495 print "大写:", \upper! 3493 print "大写:", \upper!
3496</pre> 3494</pre>
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
94-- 94--
95 95
96do 96do
97 with {a,b} = thing 97 with {a,b} := thing
98 print a, b 98 print a, b
99 99
100 100
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, ...)->
38 " 38 "
39do 39do
40 local _src_, _dst_ 40 local _src_, _dst_
41 with _dst_ = #{dst} 41 with _dst_ := #{dst}
42 with _src_ = #{src} 42 with _src_ := #{src}
43#{table.concat for field in *{...} do " 43#{table.concat for field in *{...} do "
44 _dst_.#{field} = _src_.#{field} 44 _dst_.#{field} = _src_.#{field}
45"}" 45"}"
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
220 ] 220 ]
221 print "matched", sixth 221 print "matched", sixth
222 222
223nil \ No newline at end of file 223do
224 switch v := "hello"
225 when "hello"
226 print "matched hello"
227 else
228 print "not matched"
229 -- output: matched hello
230
231do
232 f = -> "ok"
233 switch val := f!
234 when "ok"
235 print "it's ok"
236 -- output: it's ok
237
238
239do
240 g = -> 42
241 switch result := g!
242 when 1, 2
243 print "small"
244 when 42
245 print "life universe everything"
246 else
247 print "other #{result}"
248 -- output: life universe everything
249
250do
251 check = ->
252 if true
253 "yes"
254 else
255 "no"
256
257 switch x := check!
258 when "yes"
259 print "affirmative"
260 else
261 print "negative"
262 -- output: affirmative
263
264do
265 t = (): tb ->
266 tb = {a: 1}
267 tb.a = 2
268
269 switch data := t!
270 when {a: 2}
271 print "matched"
272 else
273 print "not matched"
274
275nil
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
84-- 84--
85 85
86do 86do
87 with {元素a,元素b} = 东西 87 with {元素a,元素b} := 东西
88 打印 元素a, 元素b 88 打印 元素a, 元素b
89 89
90 90
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 复制 = (源, 目标, ...)->
37 " 37 "
38do 38do
39 local _源_, _目标_ 39 local _源_, _目标_
40 with _目标_ = #{目标} 40 with _目标_ := #{目标}
41 with _源_ = #{源} 41 with _源_ := #{源}
42#{table.concat for 字段 in *{...} do " 42#{table.concat for 字段 in *{...} do "
43 _目标_.#{字段} = _源_.#{字段} 43 _目标_.#{字段} = _源_.#{字段}
44"}" 44"}"
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
45 with 变量a 45 with 变量a
46 打印 .世界 46 打印 .世界
47 47
48 模块 = with _模块 = {} 48 模块 = with _模块 := {}
49 .事物 = "你好" 49 .事物 = "你好"
50 50
51 with 变量a, 变量b = 东西, 布 51 with 变量a, 变量b := 东西, 布
52 打印 .世界 52 打印 .世界
53 53
54 变量x = with 变量a, 变量b = 1, 2 54 变量x = with 变量a, 变量b := 1, 2
55 打印 变量a + 变量b 55 打印 变量a + 变量b
56 56
57 打印 with 变量a, 变量b = 1, 2 57 打印 with 变量a, 变量b := 1, 2
58 打印 变量a + 变量b 58 打印 变量a + 变量b
59 59
60 p = with 你好!.字段x, 世界!.字段y = 1, 2 60 p = with 你好!.字段x, 世界!.字段y := 1, 2
61 打印 变量a + 变量b 61 打印 变量a + 变量b
62 62
63-- 63--
@@ -68,16 +68,16 @@ do
68 变量x\大写! 68 变量x\大写!
69 69
70do 70do
71 with 变量k = "乔" 71 with 变量k := "乔"
72 打印 \大写! 72 打印 \大写!
73 73
74do 74do
75 with 变量a,变量b,变量c = "", "", "" 75 with 变量a,变量b,变量c := "", "", ""
76 打印 \大写! 76 打印 \大写!
77 77
78do 78do
79 变量a = "床铺" 79 变量a = "床铺"
80 with 变量a,变量b,变量c = "", "", "" 80 with 变量a,变量b,变量c := "", "", ""
81 打印 \大写! 81 打印 \大写!
82 82
83do 83do
@@ -85,7 +85,7 @@ do
85 打印 \大写! 85 打印 \大写!
86 86
87do 87do
88 with 变量k.变量j = "乔" 88 with 变量k.变量j := "乔"
89 打印 \大写! 89 打印 \大写!
90 90
91do 91do
@@ -96,7 +96,7 @@ do
96 96
97do 97do
98 with 变量a 98 with 变量a
99 with .b = 2 99 with .b := 2
100 打印 .c 100 打印 .c
101 101
102do 102do
@@ -131,12 +131,12 @@ do
131 131
132do 132do
133 global 掩码 133 global 掩码
134 with? 掩码 = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 134 with? 掩码 := 实心矩形 宽: w, 高: h, 颜色: 0x66000000
135 .触摸启用 = true 135 .触摸启用 = true
136 .吞噬触摸 = true 136 .吞噬触摸 = true
137 137
138do 138do
139 with? 掩码 = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 139 with? 掩码 := 实心矩形 宽: w, 高: h, 颜色: 0x66000000
140 .触摸启用 = true 140 .触摸启用 = true
141 .吞噬触摸 = true 141 .吞噬触摸 = true
142 142
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
48 with a -- only one value allowed 48 with a -- only one value allowed
49 print .world 49 print .world
50 50
51 mod = with _M = {} 51 mod = with _M := {}
52 .Thing = "hi" 52 .Thing = "hi"
53 53
54 -- operate on a only 54 -- operate on a only
55 with a, b = something, pooh 55 with a, b := something, pooh
56 print .world 56 print .world
57 57
58 x = with a, b = 1, 2 58 x = with a, b := 1, 2
59 print a + b 59 print a + b
60 60
61 print with a, b = 1, 2 61 print with a, b := 1, 2
62 print a + b 62 print a + b
63 63
64 -- assignment lhs must be evaluated in the order they appear 64 -- assignment lhs must be evaluated in the order they appear
65 p = with hello!.x, world!.y = 1, 2 65 p = with hello!.x, world!.y := 1, 2
66 print a + b 66 print a + b
67 67
68-- 68--
@@ -73,16 +73,16 @@ do
73 x\upper! 73 x\upper!
74 74
75do 75do
76 with k = "jo" 76 with k := "jo"
77 print \upper! 77 print \upper!
78 78
79do 79do
80 with a,b,c = "", "", "" 80 with a,b,c := "", "", ""
81 print \upper! 81 print \upper!
82 82
83do 83do
84 a = "bunk" 84 a = "bunk"
85 with a,b,c = "", "", "" 85 with a,b,c := "", "", ""
86 print \upper! 86 print \upper!
87 87
88do 88do
@@ -90,7 +90,7 @@ do
90 print \upper! 90 print \upper!
91 91
92do 92do
93 with k.j = "jo" 93 with k.j := "jo"
94 print \upper! 94 print \upper!
95 95
96do 96do
@@ -103,7 +103,7 @@ do
103do 103do
104 with a 104 with a
105 -- nested `with`s with assignments should change the scope correctly 105 -- nested `with`s with assignments should change the scope correctly
106 with .b = 2 106 with .b := 2
107 print .c 107 print .c
108 108
109do 109do
@@ -138,12 +138,12 @@ do
138 138
139do 139do
140 global mask 140 global mask
141 with? mask = SolidRect width: w, height: h, color: 0x66000000 141 with? mask := SolidRect width: w, height: h, color: 0x66000000
142 .touchEnabled = true 142 .touchEnabled = true
143 .swallowTouches = true 143 .swallowTouches = true
144 144
145do 145do
146 with? mask = SolidRect width: w, height: h, color: 0x66000000 146 with? mask := SolidRect width: w, height: h, color: 0x66000000
147 .touchEnabled = true 147 .touchEnabled = true
148 .swallowTouches = true 148 .swallowTouches = true
149 149
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
1234elseif "Dan" == name or "Daniel" == name then 1234elseif "Dan" == name or "Daniel" == name then
1235 print("Your name, it's Dan") 1235 print("Your name, it's Dan")
1236else 1236else
1237 print("I don't know about your name") 1237 print("I don't know about you with name " .. tostring(name))
1238end 1238end
1239local b = 1 1239local b = 1
1240local next_number 1240local next_number
@@ -3450,7 +3450,7 @@ if "Robert" == name then
3450elseif "Dan" == name or "Daniel" == name then 3450elseif "Dan" == name or "Daniel" == name then
3451 print("Your name, it's Dan") 3451 print("Your name, it's Dan")
3452else 3452else
3453 print("I don't know about your name") 3453 print("I don't know about you with name " .. tostring(name))
3454end 3454end
3455local b = 1 3455local b = 1
3456local next_number 3456local 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
1228elseif "Dan" == name or "Daniel" == name then 1228elseif "Dan" == name or "Daniel" == name then
1229 print("你的名字是Dan") 1229 print("你的名字是Dan")
1230else 1230else
1231 print("我不知道你的名字") 1231 print("我不认识,你的名字" .. tostring(name))
1232end 1232end
1233local b = 1 1233local b = 1
1234local next_number 1234local next_number
@@ -3438,7 +3438,7 @@ if "Robert" == name then
3438elseif "Dan" == name or "Daniel" == name then 3438elseif "Dan" == name or "Daniel" == name then
3439 print("你的名字是Dan") 3439 print("你的名字是Dan")
3440else 3440else
3441 print("我不知道你的名字") 3441 print("我不认识,你的名字" .. tostring(name))
3442end 3442end
3443local b = 1 3443local b = 1
3444local next_number 3444local 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
656 end 656 end
657 end 657 end
658end 658end
659do
660 local v = "hello"
661 if "hello" == v then
662 print("matched hello")
663 else
664 print("not matched")
665 end
666end
667do
668 local f
669 f = function()
670 return "ok"
671 end
672 local val = f()
673 if "ok" == val then
674 print("it's ok")
675 end
676end
677do
678 local g
679 g = function()
680 return 42
681 end
682 local result = g()
683 if 1 == result or 2 == result then
684 print("small")
685 elseif 42 == result then
686 print("life universe everything")
687 else
688 print("other " .. tostring(result))
689 end
690end
691do
692 local check
693 check = function()
694 if true then
695 return "yes"
696 else
697 return "no"
698 end
699 end
700 local x = check()
701 if "yes" == x then
702 print("affirmative")
703 else
704 print("negative")
705 end
706end
707do
708 local t
709 t = function()
710 local tb = {
711 a = 1
712 }
713 tb.a = 2
714 return tb
715 end
716 local data = t()
717 local _type_0 = type(data)
718 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
719 local _match_0 = false
720 if _tab_0 then
721 if 2 == data.a then
722 _match_0 = true
723 print("matched")
724 end
725 end
726 if not _match_0 then
727 print("not matched")
728 end
729end
659return nil 730return 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 {
372 str_list temp{ 372 str_list temp{
373 eop ? "with?"s : "with"s, 373 eop ? "with?"s : "with"s,
374 valueList->to_string(ud)}; 374 valueList->to_string(ud)};
375 if (assigns) { 375 if (assign) {
376 temp.push_back(assigns->to_string(ud)); 376 temp.push_back(':' + assign->to_string(ud));
377 } 377 }
378 if (body.is<Statement_t>()) { 378 if (body.is<Statement_t>()) {
379 return join(temp, " "sv) + " do "s + body->to_string(ud); 379 return join(temp, " "sv) + " do "s + body->to_string(ud);
@@ -419,6 +419,9 @@ std::string SwitchCase_t::to_string(void* ud) const {
419std::string Switch_t::to_string(void* ud) const { 419std::string Switch_t::to_string(void* ud) const {
420 auto info = reinterpret_cast<YueFormat*>(ud); 420 auto info = reinterpret_cast<YueFormat*>(ud);
421 str_list temp{"switch "s + target->to_string(ud)}; 421 str_list temp{"switch "s + target->to_string(ud)};
422 if (assignment) {
423 temp.back().append(" :"s + assignment->to_string(ud));
424 }
422 info->pushScope(); 425 info->pushScope();
423 for (auto branch : branches.objects()) { 426 for (auto branch : branches.objects()) {
424 temp.emplace_back(info->ind() + branch->to_string(ud)); 427 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)
287AST_NODE(With) 287AST_NODE(With)
288 ast_ptr<false, ExistentialOp_t> eop; 288 ast_ptr<false, ExistentialOp_t> eop;
289 ast_ptr<true, ExpList_t> valueList; 289 ast_ptr<true, ExpList_t> valueList;
290 ast_ptr<false, Assign_t> assigns; 290 ast_ptr<false, Assign_t> assign;
291 ast_sel<true, Block_t, Statement_t> body; 291 ast_sel<true, Block_t, Statement_t> body;
292 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 292 AST_MEMBER(With, &eop, &valueList, &assign, &body)
293AST_END(With) 293AST_END(With)
294 294
295AST_NODE(SwitchList) 295AST_NODE(SwitchList)
@@ -304,20 +304,21 @@ AST_NODE(SwitchCase)
304 AST_MEMBER(SwitchCase, &condition, &body) 304 AST_MEMBER(SwitchCase, &condition, &body)
305AST_END(SwitchCase) 305AST_END(SwitchCase)
306 306
307AST_NODE(Assignment)
308 ast_ptr<false, ExpList_t> expList;
309 ast_ptr<true, Assign_t> assign;
310 AST_MEMBER(Assignment, &expList, &assign)
311AST_END(Assignment)
312
307AST_NODE(Switch) 313AST_NODE(Switch)
308 ast_ptr<true, Exp_t> target; 314 ast_ptr<true, Exp_t> target;
315 ast_ptr<false, Assignment_t> assignment;
309 ast_ptr<true, Seperator_t> sep; 316 ast_ptr<true, Seperator_t> sep;
310 ast_list<true, SwitchCase_t> branches; 317 ast_list<true, SwitchCase_t> branches;
311 ast_sel<false, Block_t, Statement_t> lastBranch; 318 ast_sel<false, Block_t, Statement_t> lastBranch;
312 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) 319 AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch)
313AST_END(Switch) 320AST_END(Switch)
314 321
315AST_NODE(Assignment)
316 ast_ptr<false, ExpList_t> expList;
317 ast_ptr<true, Assign_t> assign;
318 AST_MEMBER(Assignment, &expList, &assign)
319AST_END(Assignment)
320
321AST_NODE(IfCond) 322AST_NODE(IfCond)
322 ast_ptr<true, Exp_t> condition; 323 ast_ptr<true, Exp_t> condition;
323 ast_ptr<false, Assignment_t> assignment; 324 ast_ptr<false, Assignment_t> 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<std::string> Metamethods = {
78 "close"s // Lua 5.4 78 "close"s // Lua 5.4
79}; 79};
80 80
81const std::string_view version = "0.28.3"sv; 81const std::string_view version = "0.28.4"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class CompileError : public std::logic_error {
@@ -9370,11 +9370,11 @@ private:
9370 std::string withVar; 9370 std::string withVar;
9371 bool needScope = !currentScope().lastStatement && !returnValue; 9371 bool needScope = !currentScope().lastStatement && !returnValue;
9372 bool extraScope = false; 9372 bool extraScope = false;
9373 if (with->assigns) { 9373 if (with->assign) {
9374 auto vars = getAssignVars(with); 9374 auto vars = getAssignVars(with);
9375 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 9375 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9376 if (with->assigns->values.objects().size() == 1) { 9376 if (with->assign->values.objects().size() == 1) {
9377 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 9377 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9378 if (!var.empty() && isLocal(var)) { 9378 if (!var.empty() && isLocal(var)) {
9379 withVar = var; 9379 withVar = var;
9380 } 9380 }
@@ -9384,7 +9384,7 @@ private:
9384 auto assignment = x->new_ptr<ExpListAssign_t>(); 9384 auto assignment = x->new_ptr<ExpListAssign_t>();
9385 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 9385 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9386 auto assign = x->new_ptr<Assign_t>(); 9386 auto assign = x->new_ptr<Assign_t>();
9387 assign->values.push_back(with->assigns->values.objects().front()); 9387 assign->values.push_back(with->assign->values.objects().front());
9388 assignment->action.set(assign); 9388 assignment->action.set(assign);
9389 if (needScope) { 9389 if (needScope) {
9390 extraScope = true; 9390 extraScope = true;
@@ -9398,7 +9398,7 @@ private:
9398 auto assign = x->new_ptr<Assign_t>(); 9398 auto assign = x->new_ptr<Assign_t>();
9399 assign->values.push_back(toAst<Exp_t>(withVar, x)); 9399 assign->values.push_back(toAst<Exp_t>(withVar, x));
9400 bool skipFirst = true; 9400 bool skipFirst = true;
9401 for (auto value : with->assigns->values.objects()) { 9401 for (auto value : with->assign->values.objects()) {
9402 if (skipFirst) { 9402 if (skipFirst) {
9403 skipFirst = false; 9403 skipFirst = false;
9404 continue; 9404 continue;
@@ -9411,7 +9411,7 @@ private:
9411 withVar = vars.front(); 9411 withVar = vars.front();
9412 auto assignment = x->new_ptr<ExpListAssign_t>(); 9412 auto assignment = x->new_ptr<ExpListAssign_t>();
9413 assignment->expList.set(with->valueList); 9413 assignment->expList.set(with->valueList);
9414 assignment->action.set(with->assigns); 9414 assignment->action.set(with->assign);
9415 if (needScope) { 9415 if (needScope) {
9416 extraScope = true; 9416 extraScope = true;
9417 temp.push_back(indent() + "do"s + nll(with)); 9417 temp.push_back(indent() + "do"s + nll(with));
@@ -10760,10 +10760,26 @@ private:
10760 pushScope(); 10760 pushScope();
10761 } 10761 }
10762 bool extraScope = false; 10762 bool extraScope = false;
10763 if (switchNode->assignment) {
10764 if (needScope) {
10765 extraScope = true;
10766 temp.push_back(indent() + "do"s + nll(x));
10767 pushScope();
10768 }
10769 auto asmt = x->new_ptr<ExpListAssign_t>();
10770 auto expList = x->new_ptr<ExpList_t>();
10771 expList->exprs.push_back(switchNode->target);
10772 if (switchNode->assignment->expList) {
10773 expList->exprs.dup(switchNode->assignment->expList->exprs);
10774 }
10775 asmt->expList.set(expList);
10776 asmt->action.set(switchNode->assignment->assign);
10777 transformAssignment(asmt, temp);
10778 }
10763 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 10779 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10764 if (objVar.empty() || !isLocal(objVar)) { 10780 if (objVar.empty() || !isLocal(objVar)) {
10765 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 10781 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10766 if (needScope) { 10782 if (needScope && !extraScope) {
10767 extraScope = true; 10783 extraScope = true;
10768 temp.push_back(indent() + "do"s + nll(x)); 10784 temp.push_back(indent() + "do"s + nll(x));
10769 pushScope(); 10785 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() {
118 return false; 118 return false;
119 }); 119 });
120 120
121 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 121 assignment_expression_syntax_error = pl::user(true_(), [](const item_t& item) {
122 throw ParserError("use := for if-assignment expression"sv, item.begin); 122 throw ParserError("use := for assignment expression"sv, item.begin);
123 return false; 123 return false;
124 }); 124 });
125 125
@@ -356,7 +356,7 @@ YueParser::YueParser() {
356 356
357 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 357 Return = key("return") >> -(space >> (TableBlock | ExpListLow));
358 358
359 with_exp = ExpList >> -(space >> Assign); 359 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error));
360 360
361 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); 361 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do");
362 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); 362 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then");
@@ -372,7 +372,8 @@ YueParser::YueParser() {
372 and_(SimpleTable | TableLit) >> Exp | 372 and_(SimpleTable | TableLit) >> Exp |
373 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 373 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab)
374 ); 374 );
375 Switch = key("switch") >> space >> Exp >> 375 Switch = key("switch") >> space >>
376 Exp >> -(space >> Assignment) >>
376 space >> Seperator >> ( 377 space >> Seperator >> (
377 SwitchCase >> space >> ( 378 SwitchCase >> space >> (
378 switch_block | 379 switch_block |
@@ -381,7 +382,7 @@ YueParser::YueParser() {
381 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 382 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
382 ); 383 );
383 384
384 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 385 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
385 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); 386 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment)));
386 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); 387 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then");
387 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; 388 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:
156 NONE_AST_RULE(invalid_interpolation_error); 156 NONE_AST_RULE(invalid_interpolation_error);
157 NONE_AST_RULE(confusing_unary_not_error); 157 NONE_AST_RULE(confusing_unary_not_error);
158 NONE_AST_RULE(table_key_pair_error); 158 NONE_AST_RULE(table_key_pair_error);
159 NONE_AST_RULE(if_assignment_syntax_error); 159 NONE_AST_RULE(assignment_expression_syntax_error);
160 160
161 NONE_AST_RULE(inc_exp_level); 161 NONE_AST_RULE(inc_exp_level);
162 NONE_AST_RULE(dec_exp_level); 162 NONE_AST_RULE(dec_exp_level);