aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2022-07-14 02:48:49 +0800
committerLi Jin <dragon-fly@qq.com>2022-07-14 02:48:49 +0800
commit3159a45de9e691ad758dcbc933446f61b7ae1940 (patch)
treeb695f8356986accc84c82ece09eb427a2b1db230
parenta1d341085eed96d567329a30f2cf57c95fe6f071 (diff)
downloadyuescript-3159a45de9e691ad758dcbc933446f61b7ae1940.tar.gz
yuescript-3159a45de9e691ad758dcbc933446f61b7ae1940.tar.bz2
yuescript-3159a45de9e691ad758dcbc933446f61b7ae1940.zip
fix table matching issue and update doc.
-rwxr-xr-xdoc/docs/doc/README.md119
-rw-r--r--spec/inputs/switch.yue6
-rw-r--r--spec/outputs/switch.lua28
-rwxr-xr-xsrc/yuescript/yue_compiler.cpp72
4 files changed, 176 insertions, 49 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md
index 5d856bb..ef00c23 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -311,7 +311,7 @@ end
311 311
312### Export Macro 312### Export Macro
313 313
314Macro functions can be exported from a module and get imported in another module. It is recommanded to export macro functions in a single file to speed up compilation. 314Macro functions can be exported from a module and get imported in another module. You have to put export macro functions in a single file to be used, and only macro definition, macro importing and macro expansion in place can be put into the macro exporting module.
315```moonscript 315```moonscript
316-- file: utils.yue 316-- file: utils.yue
317export macro map = (items, action)-> "[#{action} for _ in *#{items}]" 317export macro map = (items, action)-> "[#{action} for _ in *#{items}]"
@@ -345,6 +345,20 @@ import "utils" as {
345</pre> 345</pre>
346</YueDisplay> 346</YueDisplay>
347 347
348### Builtin Macro
349
350There are some builtin macros but you can override them by declaring macros with the same names.
351```moonscript
352print $FILE -- get string of current module name
353print $LINE -- get number 2
354```
355<YueDisplay>
356<pre>
357print $FILE -- get string of current module name
358print $LINE -- get number 2
359</pre>
360</YueDisplay>
361
348## Operator 362## Operator
349 363
350All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes. 364All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes.
@@ -1237,10 +1251,6 @@ close _ = close#: -> print "Out of scope."
1237</pre> 1251</pre>
1238</YueDisplay> 1252</YueDisplay>
1239 1253
1240::: warning NOTICE
1241The rest of the document is describing mostly the same syntax taken from Moonscript. So you may as well refer to the [Moonscript Reference](http://moonscript.org/reference) to get the same explanation.
1242:::
1243
1244## Literals 1254## Literals
1245 1255
1246All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**. 1256All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**.
@@ -2295,6 +2305,60 @@ msg = switch math.random(1, 5)
2295 2305
2296It is worth noting the order of the case comparison expression. The case’s expression is on the left hand side. This can be useful if the case’s expression wants to overwrite how the comparison is done by defining an eq metamethod. 2306It is worth noting the order of the case comparison expression. The case’s expression is on the left hand side. This can be useful if the case’s expression wants to overwrite how the comparison is done by defining an eq metamethod.
2297 2307
2308### Table Matching
2309
2310You can do table matching in a switch when clause, if the table can be destructured by a specific structure and get non-nil values.
2311
2312```moonscript
2313items =
2314 * x: 100
2315 y: 200
2316 * width: 300
2317 height: 400
2318
2319for item in *items
2320 switch item
2321 when :x, :y
2322 print "Vec2 #{x}, #{y}"
2323 when :width, :height
2324 print "size #{width}, #{height}"
2325```
2326<YueDisplay>
2327<pre>
2328items =
2329 * x: 100
2330 y: 200
2331 * width: 300
2332 height: 400
2333
2334for item in *items
2335 switch item
2336 when :x, :y
2337 print "Vec2 #{x}, #{y}"
2338 when :width, :height
2339 print "size #{width}, #{height}"
2340</pre>
2341</YueDisplay>
2342
2343You can use default values to optionally destructure the table for some fields.
2344
2345```moonscript
2346item = x: 100
2347
2348switch item
2349 when {:x, :y = 200}
2350 print "Vec2 #{x}, #{y}" -- table matching will pass
2351```
2352<YueDisplay>
2353<pre>
2354item = x: 100
2355
2356switch item
2357 when {:x, :y = 200}
2358 print "Vec2 #{x}, #{y}" -- table matching will pass
2359</pre>
2360</YueDisplay>
2361
2298## Object Oriented Programming 2362## Object Oriented Programming
2299 2363
2300In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the Yuescript code at first, then look into the Lua code if you wish to know the implementation details. 2364In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the Yuescript code at first, then look into the Lua code if you wish to know the implementation details.
@@ -2718,6 +2782,51 @@ x = class
2718</pre> 2782</pre>
2719</YueDisplay> 2783</YueDisplay>
2720 2784
2785### Class Mixing
2786
2787You can do mixing with keyword `using` to copy functions from either a plain table or a predefined class object into your new class. When doing mixing with a plain table, you can override the class indexing function (metamethod `__index`) to your customized implementation. When doing mixing with an existing class object, the class object's metamethods won't be copied.
2788
2789```moonscript
2790MyIndex = __index: var: 1
2791
2792class X using MyIndex
2793 func: =>
2794 print 123
2795
2796x = X!
2797print x.var
2798
2799class Y using X
2800
2801y = Y!
2802y\func!
2803
2804assert y.__class.__parent ~= X -- X is not parent of Y
2805```
2806<YueDisplay>
2807<pre>
2808MyIndex = __index: var: 1
2809
2810class X using MyIndex
2811 func: =>
2812 print 123
2813
2814x = X!
2815print x.var
2816
2817class Y using X
2818
2819y = Y!
2820y\func!
2821
2822assert y.__class.__parent ~= X -- X is not parent of Y
2823</pre>
2824</YueDisplay>
2825
2826::: warning NOTICE
2827The rest of the document is describing mostly the same syntax taken from Moonscript. So you may as well refer to the [Moonscript Reference](http://moonscript.org/reference) to get the same explanation.
2828:::
2829
2721## With Statement 2830## With Statement
2722 2831
2723A common pattern involving the creation of an object is calling a series of functions and setting a series of properties immediately after creating it. 2832A common pattern involving the creation of an object is calling a series of functions and setting a series of properties immediately after creating it.
diff --git a/spec/inputs/switch.yue b/spec/inputs/switch.yue
index 36f9be6..04bb02e 100644
--- a/spec/inputs/switch.yue
+++ b/spec/inputs/switch.yue
@@ -139,10 +139,10 @@ do
139 "#{a + b}" 139 "#{a + b}"
140 when 1, 2, 3, 4, 5 140 when 1, 2, 3, 4, 5
141 "number 1 - 5" 141 "number 1 - 5"
142 when {:alwaysMatch = "fallback"} 142 when {:matchAnyTable = "fallback"}
143 alwaysMatch 143 matchAnyTable
144 else 144 else
145 "should not reach here" 145 "should not reach here unless it is not a table"
146 146
147nil 147nil
148 148
diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua
index 03a0d37..7b413f8 100644
--- a/spec/outputs/switch.lua
+++ b/spec/outputs/switch.lua
@@ -182,8 +182,8 @@ do
182 local x = item.x 182 local x = item.x
183 local y = item.y 183 local y = item.y
184 if x ~= nil and y ~= nil then 184 if x ~= nil and y ~= nil then
185 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
186 _match_0 = true 185 _match_0 = true
186 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
187 end 187 end
188 end 188 end
189 if not _match_0 then 189 if not _match_0 then
@@ -192,8 +192,8 @@ do
192 local width = item.width 192 local width = item.width
193 local height = item.height 193 local height = item.height
194 if width ~= nil and height ~= nil then 194 if width ~= nil and height ~= nil then
195 print("Size " .. tostring(width) .. ", " .. tostring(height))
196 _match_1 = true 195 _match_1 = true
196 print("Size " .. tostring(width) .. ", " .. tostring(height))
197 end 197 end
198 end 198 end
199 if not _match_1 then 199 if not _match_1 then
@@ -204,12 +204,12 @@ do
204 if _tab_0 then 204 if _tab_0 then
205 local cls = item.__class 205 local cls = item.__class
206 if cls ~= nil then 206 if cls ~= nil then
207 _match_2 = true
207 if ClassA == cls then 208 if ClassA == cls then
208 print("Object A") 209 print("Object A")
209 elseif ClassB == cls then 210 elseif ClassB == cls then
210 print("Object B") 211 print("Object B")
211 end 212 end
212 _match_2 = true
213 end 213 end
214 end 214 end
215 if not _match_2 then 215 if not _match_2 then
@@ -241,9 +241,7 @@ do
241 if b == nil then 241 if b == nil then
242 b = 2 242 b = 2
243 end 243 end
244 if a ~= nil and b ~= nil then 244 print(a, b)
245 print(a, b)
246 end
247 end 245 end
248 end 246 end
249end 247end
@@ -258,8 +256,8 @@ do
258 local x = tb.x 256 local x = tb.x
259 local y = tb.y 257 local y = tb.y
260 if x ~= nil and y ~= nil then 258 if x ~= nil and y ~= nil then
261 print("x: " .. tostring(x) .. " with y: " .. tostring(y))
262 _match_0 = true 259 _match_0 = true
260 print("x: " .. tostring(x) .. " with y: " .. tostring(y))
263 end 261 end
264 end 262 end
265 if not _match_0 then 263 if not _match_0 then
@@ -284,8 +282,8 @@ do
284 if _tab_0 then 282 if _tab_0 then
285 local x = _exp_0.x 283 local x = _exp_0.x
286 if x ~= nil then 284 if x ~= nil then
287 matched = x
288 _match_0 = true 285 _match_0 = true
286 matched = x
289 end 287 end
290 end 288 end
291 if not _match_0 then 289 if not _match_0 then
@@ -310,8 +308,8 @@ do
310 local a = _exp_0.a 308 local a = _exp_0.a
311 local b = _exp_0.b 309 local b = _exp_0.b
312 if a ~= nil and b ~= nil then 310 if a ~= nil and b ~= nil then
313 return tostring(a + b)
314 _match_0 = true 311 _match_0 = true
312 return tostring(a + b)
315 end 313 end
316 end 314 end
317 if not _match_0 then 315 if not _match_0 then
@@ -319,15 +317,13 @@ do
319 return "number 1 - 5" 317 return "number 1 - 5"
320 else 318 else
321 if _tab_0 then 319 if _tab_0 then
322 local alwaysMatch = _exp_0.alwaysMatch 320 local matchAnyTable = _exp_0.matchAnyTable
323 if alwaysMatch == nil then 321 if matchAnyTable == nil then
324 alwaysMatch = "fallback" 322 matchAnyTable = "fallback"
325 end
326 if alwaysMatch ~= nil then
327 return alwaysMatch
328 end 323 end
324 return matchAnyTable
329 else 325 else
330 return "should not reach here" 326 return "should not reach here unless it is not a table"
331 end 327 end
332 end 328 end
333 end 329 end
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index c68746c..2565878 100755
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -56,7 +56,7 @@ using namespace parserlib;
56 56
57typedef std::list<std::string> str_list; 57typedef std::list<std::string> str_list;
58 58
59const std::string_view version = "0.13.3"sv; 59const std::string_view version = "0.13.4"sv;
60const std::string_view extension = "yue"sv; 60const std::string_view extension = "yue"sv;
61 61
62class YueCompilerImpl { 62class YueCompilerImpl {
@@ -1582,12 +1582,22 @@ private:
1582 added--; 1582 added--;
1583 } 1583 }
1584 if (pair.defVal) { 1584 if (pair.defVal) {
1585 auto stmt = toAst<Statement_t>(pair.targetVar + "=nil if "s + pair.targetVar + "==nil", pair.defVal); 1585 bool isNil = false;
1586 auto defAssign = stmt->content.as<ExpListAssign_t>(); 1586 if (auto v1 = singleValueFrom(pair.defVal)) {
1587 auto assign = defAssign->action.as<Assign_t>(); 1587 if (auto v2 = v1->item.as<SimpleValue_t>()) {
1588 assign->values.clear(); 1588 if (auto v3 = v2->value.as<const_value_t>()) {
1589 assign->values.push_back(pair.defVal); 1589 isNil = _parser.toString(v3) == "nil"sv;
1590 transformStatement(stmt, temp); 1590 }
1591 }
1592 }
1593 if (!isNil) {
1594 auto stmt = toAst<Statement_t>(pair.targetVar + "=nil if "s + pair.targetVar + "==nil", pair.defVal);
1595 auto defAssign = stmt->content.as<ExpListAssign_t>();
1596 auto assign = defAssign->action.as<Assign_t>();
1597 assign->values.clear();
1598 assign->values.push_back(pair.defVal);
1599 transformStatement(stmt, temp);
1600 }
1591 } 1601 }
1592 continue; 1602 continue;
1593 } 1603 }
@@ -1709,12 +1719,22 @@ private:
1709 } 1719 }
1710 for (const auto& item : destruct.items) { 1720 for (const auto& item : destruct.items) {
1711 if (item.defVal) { 1721 if (item.defVal) {
1712 auto stmt = toAst<Statement_t>(item.targetVar + "=nil if "s + item.targetVar + "==nil", item.defVal); 1722 bool isNil = false;
1713 auto defAssign = stmt->content.as<ExpListAssign_t>(); 1723 if (auto v1 = singleValueFrom(item.defVal)) {
1714 auto assign = defAssign->action.as<Assign_t>(); 1724 if (auto v2 = v1->item.as<SimpleValue_t>()) {
1715 assign->values.clear(); 1725 if (auto v3 = v2->value.as<const_value_t>()) {
1716 assign->values.push_back(item.defVal); 1726 isNil = _parser.toString(v3) == "nil"sv;
1717 transformStatement(stmt, temp); 1727 }
1728 }
1729 }
1730 if (!isNil) {
1731 auto stmt = toAst<Statement_t>(item.targetVar + "=nil if "s + item.targetVar + "==nil", item.defVal);
1732 auto defAssign = stmt->content.as<ExpListAssign_t>();
1733 auto assign = defAssign->action.as<Assign_t>();
1734 assign->values.clear();
1735 assign->values.push_back(item.defVal);
1736 transformStatement(stmt, temp);
1737 }
1718 } 1738 }
1719 } 1739 }
1720 for (const auto& item : leftPairs) { 1740 for (const auto& item : leftPairs) {
@@ -7160,32 +7180,34 @@ private:
7160 auto assignment = assignmentFrom(static_cast<Exp_t*>(branch->valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch); 7180 auto assignment = assignmentFrom(static_cast<Exp_t*>(branch->valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch);
7161 auto info = extractDestructureInfo(assignment, true, false); 7181 auto info = extractDestructureInfo(assignment, true, false);
7162 transformAssignment(assignment, temp, true); 7182 transformAssignment(assignment, temp, true);
7163 temp.push_back(indent() + "if"s); 7183 str_list conds;
7164 bool firstItem = true;
7165 for (const auto& destruct : info.first) { 7184 for (const auto& destruct : info.first) {
7166 for (const auto& item : destruct.items) { 7185 for (const auto& item : destruct.items) {
7167 str_list tmp; 7186 if (!item.defVal) {
7168 transformExp(item.target, tmp, ExpUsage::Closure); 7187 transformExp(item.target, conds, ExpUsage::Closure);
7169 temp.back().append((firstItem ? " " : " and "s) + tmp.back() + " ~= nil"s); 7188 conds.back().append(" ~= nil"s);
7170 if (firstItem) firstItem = false; 7189 }
7171 } 7190 }
7172 } 7191 }
7173 temp.back().append(" then"s + nll(branch)); 7192 if (!conds.empty()) {
7174 pushScope(); 7193 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nll(branch));
7175 transform_plain_body(branch->body, temp, usage, assignList); 7194 pushScope();
7195 }
7176 if (!lastBranch) { 7196 if (!lastBranch) {
7177 temp.push_back(indent() + matchVar + " = true"s + nll(branch)); 7197 temp.push_back(indent() + matchVar + " = true"s + nll(branch));
7178 } 7198 }
7179 popScope(); 7199 transform_plain_body(branch->body, temp, usage, assignList);
7180 if (!lastBranch) { 7200 if (!conds.empty()) {
7201 popScope();
7181 temp.push_back(indent() + "end"s + nll(branch)); 7202 temp.push_back(indent() + "end"s + nll(branch));
7203 }
7204 if (!lastBranch) {
7182 popScope(); 7205 popScope();
7183 temp.push_back(indent() + "end"s + nll(branch)); 7206 temp.push_back(indent() + "end"s + nll(branch));
7184 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch)); 7207 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch));
7185 pushScope(); 7208 pushScope();
7186 addScope++; 7209 addScope++;
7187 } else { 7210 } else {
7188 temp.push_back(indent() + "end"s + nll(branch));
7189 popScope(); 7211 popScope();
7190 } 7212 }
7191 firstBranch = true; 7213 firstBranch = true;