aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-08-26 12:50:50 +0800
committerLi Jin <dragon-fly@qq.com>2025-08-26 12:50:50 +0800
commitd90857cc05cd0820a2057c547e95b02d24d15412 (patch)
tree7cd1fb7ecff4799140eb96d5c3d7f48a3c76edc7
parent99692899d1e793e2cbbaea03107cb0a5f5e5c452 (diff)
downloadyuescript-d90857cc05cd0820a2057c547e95b02d24d15412.tar.gz
yuescript-d90857cc05cd0820a2057c547e95b02d24d15412.tar.bz2
yuescript-d90857cc05cd0820a2057c547e95b02d24d15412.zip
Added function argument destructuring.
-rw-r--r--spec/inputs/funcs.yue31
-rw-r--r--spec/outputs/funcs.lua153
-rw-r--r--src/yuescript/yue_ast.h2
-rw-r--r--src/yuescript/yue_compiler.cpp54
-rw-r--r--src/yuescript/yue_parser.cpp2
5 files changed, 237 insertions, 5 deletions
diff --git a/spec/inputs/funcs.yue b/spec/inputs/funcs.yue
index e647edc..6b1669b 100644
--- a/spec/inputs/funcs.yue
+++ b/spec/inputs/funcs.yue
@@ -193,4 +193,35 @@ do
193 func = (): -> check 123 193 func = (): -> check 123
194 print func! -- get nil 194 print func! -- get nil
195 195
196do
197 f = ({:a, :b, :c}) -> print a, b, c
198 f = (:a, :b, :c) -> print a, b, c
199 g = (x, :y) -> print x, y
200 i = ({a: ax = 0, b: by = 0}) -> print ax, by
201 j = (name, {id: uid = "n/a", :role = "guest"}) -> print name, uid, role
202 m = ({user: {:name, :age}, meta: {:ver = 1}}) -> print name, age, ver
203 m1 = ({user: {:name, :age}, :meta = {}}) -> print name, age, meta and meta.ver or "nil"
204 new = ({:name = "anon", :age = 0}) =>
205 @name = name
206 @age = age
207 set = ({:name = @name, :age = @age}) =>
208 @name = name
209 @age = age
210 logKV = ({:k, :v}, ...) ->
211 print "kv:", k, v
212 print "rest count:", select "#", ...
213 macro gen = (fname) -> |
214 #{fname} = ({:a, :b = 0}) -> print a, b
215 $gen foo
216 t1 = (:a, x) -> print a, x
217 t2 = (:a) -> print a
218 w = (
219 id
220 {:x = 0, :y = 0}
221 :flag
222 ) ->
223 print id, x, y, flag
224 g1 = ({:a, a: ax}) -> print a, ax
225 g4 = ({:a, :b, ...rest}) -> print a, b
226
196nil 227nil
diff --git a/spec/outputs/funcs.lua b/spec/outputs/funcs.lua
index c1735c4..db7ed67 100644
--- a/spec/outputs/funcs.lua
+++ b/spec/outputs/funcs.lua
@@ -283,4 +283,157 @@ do
283 end 283 end
284 print(func()) 284 print(func())
285end 285end
286local _anon_func_0 = function(_arg_0)
287 local _accum_0 = { }
288 local _len_0 = 1
289 local _max_0 = #_arg_0
290 for _index_0 = 1, _max_0 do
291 local _item_0 = _arg_0[_index_0]
292 _accum_0[_len_0] = _item_0
293 _len_0 = _len_0 + 1
294 end
295 return _accum_0
296end
297do
298 local f
299 f = function(_arg_0)
300 local a, b, c
301 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
302 return print(a, b, c)
303 end
304 f = function(_arg_0)
305 local a, b, c
306 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
307 return print(a, b, c)
308 end
309 local g
310 g = function(x, _arg_0)
311 local y
312 y = _arg_0.y
313 return print(x, y)
314 end
315 local i
316 i = function(_arg_0)
317 local ax, by
318 ax, by = _arg_0.a, _arg_0.b
319 if ax == nil then
320 ax = 0
321 end
322 if by == nil then
323 by = 0
324 end
325 return print(ax, by)
326 end
327 j = function(name, _arg_0)
328 local uid, role
329 uid, role = _arg_0.id, _arg_0.role
330 if uid == nil then
331 uid = "n/a"
332 end
333 if role == nil then
334 role = "guest"
335 end
336 return print(name, uid, role)
337 end
338 local m
339 m = function(_arg_0)
340 local name, age, ver
341 name, age, ver = _arg_0.user.name, _arg_0.user.age, _arg_0.meta.ver
342 if ver == nil then
343 ver = 1
344 end
345 return print(name, age, ver)
346 end
347 local m1
348 m1 = function(_arg_0)
349 local name, age, meta
350 name, age, meta = _arg_0.user.name, _arg_0.user.age, _arg_0.meta
351 if meta == nil then
352 meta = { }
353 end
354 return print(name, age, meta and meta.ver or "nil")
355 end
356 local new
357 new = function(self, _arg_0)
358 local name, age
359 name, age = _arg_0.name, _arg_0.age
360 if name == nil then
361 name = "anon"
362 end
363 if age == nil then
364 age = 0
365 end
366 self.name = name
367 self.age = age
368 end
369 local set
370 set = function(self, _arg_0)
371 local name, age
372 name, age = _arg_0.name, _arg_0.age
373 if name == nil then
374 name = self.name
375 end
376 if age == nil then
377 age = self.age
378 end
379 self.name = name
380 self.age = age
381 end
382 local logKV
383 logKV = function(_arg_0, ...)
384 local k, v
385 k, v = _arg_0.k, _arg_0.v
386 print("kv:", k, v)
387 return print("rest count:", select("#", ...))
388 end
389 do
390 local foo
391 foo = function(_arg_0)
392 local a, b
393 a, b = _arg_0.a, _arg_0.b
394 if b == nil then
395 b = 0
396 end
397 return print(a, b)
398 end
399 end
400 local t1
401 t1 = function(_arg_0, x)
402 local a
403 a = _arg_0.a
404 return print(a, x)
405 end
406 local t2
407 t2 = function(_arg_0)
408 local a
409 a = _arg_0.a
410 return print(a)
411 end
412 local w
413 w = function(id, _arg_0, _arg_1)
414 local x, y
415 x, y = _arg_0.x, _arg_0.y
416 if x == nil then
417 x = 0
418 end
419 if y == nil then
420 y = 0
421 end
422 local flag
423 flag = _arg_1.flag
424 return print(id, x, y, flag)
425 end
426 local g1
427 g1 = function(_arg_0)
428 local a, ax
429 a, ax = _arg_0.a, _arg_0.a
430 return print(a, ax)
431 end
432 local g4
433 g4 = function(_arg_0)
434 local a, b, rest
435 a, b, rest = _arg_0.a, _arg_0.b, _anon_func_0(_arg_0)
436 return print(a, b)
437 end
438end
286return nil 439return nil
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 1937eb8..6e1bb88 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -780,7 +780,7 @@ AST_NODE(Export)
780AST_END(Export) 780AST_END(Export)
781 781
782AST_NODE(FnArgDef) 782AST_NODE(FnArgDef)
783 ast_sel<true, Variable_t, SelfItem_t> name; 783 ast_sel<true, Variable_t, SelfItem_t, SimpleTable_t, TableLit_t> name;
784 ast_ptr<false, ExistentialOp_t> op; 784 ast_ptr<false, ExistentialOp_t> op;
785 ast_ptr<false, Name_t> label; 785 ast_ptr<false, Name_t> label;
786 ast_ptr<false, Exp_t> defaultValue; 786 ast_ptr<false, Exp_t> defaultValue;
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index d676750..33161a7 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.29.3"sv; 81const std::string_view version = "0.29.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 {
@@ -1982,7 +1982,7 @@ private:
1982 return indent() + "local "s + join(defs, ", "sv); 1982 return indent() + "local "s + join(defs, ", "sv);
1983 } 1983 }
1984 1984
1985 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 1985 std::string getDestructureDefine(ExpListAssign_t* assignment) {
1986 auto info = extractDestructureInfo(assignment, true, false); 1986 auto info = extractDestructureInfo(assignment, true, false);
1987 if (!info.destructures.empty()) { 1987 if (!info.destructures.empty()) {
1988 str_list defs; 1988 str_list defs;
@@ -2013,8 +2013,31 @@ private:
2013 return clearBuf(); 2013 return clearBuf();
2014 } 2014 }
2015 2015
2016 str_list getArgDestructureList(ExpListAssign_t* assignment) {
2017 str_list defs;
2018 auto info = extractDestructureInfo(assignment, true, false);
2019 if (!info.destructures.empty()) {
2020 for (const auto& des : info.destructures) {
2021 if (std::holds_alternative<Destructure>(des)) {
2022 const auto& destruct = std::get<Destructure>(des);
2023 for (const auto& item : destruct.items) {
2024 if (item.targetVar.empty()) {
2025 throw CompileError("can only destruct argument to variable"sv, item.target);
2026 } else {
2027 defs.push_back(item.targetVar);
2028 }
2029 }
2030 } else {
2031 const auto& assignment = std::get<AssignmentPtr>(des);
2032 YUEE("AST node mismatch", assignment.ptr);
2033 }
2034 }
2035 }
2036 return defs;
2037 }
2038
2016 std::string getPreDefine(ExpListAssign_t* assignment) { 2039 std::string getPreDefine(ExpListAssign_t* assignment) {
2017 auto preDefine = getDestrucureDefine(assignment); 2040 auto preDefine = getDestructureDefine(assignment);
2018 if (preDefine.empty()) { 2041 if (preDefine.empty()) {
2019 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); 2042 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark));
2020 } 2043 }
@@ -5652,6 +5675,7 @@ private:
5652 bool checkExistence = false; 5675 bool checkExistence = false;
5653 std::string name; 5676 std::string name;
5654 std::string assignSelf; 5677 std::string assignSelf;
5678 ast_ptr<false, ExpListAssign_t> assignment;
5655 }; 5679 };
5656 std::list<ArgItem> argItems; 5680 std::list<ArgItem> argItems;
5657 str_list temp; 5681 str_list temp;
@@ -5706,6 +5730,22 @@ private:
5706 } 5730 }
5707 break; 5731 break;
5708 } 5732 }
5733 case id<TableLit_t>(): {
5734 arg.name = getUnusedName("_arg_"sv);
5735 auto simpleValue = def->new_ptr<SimpleValue_t>();
5736 simpleValue->value.set(def->name);
5737 auto asmt = assignmentFrom(newExp(simpleValue, def), toAst<Exp_t>(arg.name, def), def);
5738 arg.assignment = asmt;
5739 break;
5740 }
5741 case id<SimpleTable_t>(): {
5742 arg.name = getUnusedName("_arg_"sv);
5743 auto value = def->new_ptr<Value_t>();
5744 value->item.set(def->name);
5745 auto asmt = assignmentFrom(newExp(value, def), toAst<Exp_t>(arg.name, def), def);
5746 arg.assignment = asmt;
5747 break;
5748 }
5709 default: YUEE("AST node mismatch", def->name.get()); break; 5749 default: YUEE("AST node mismatch", def->name.get()); break;
5710 } 5750 }
5711 forceAddToScope(arg.name); 5751 forceAddToScope(arg.name);
@@ -5724,6 +5764,14 @@ private:
5724 _buf << indent() << "end"sv << nll(def); 5764 _buf << indent() << "end"sv << nll(def);
5725 temp.back() = clearBuf(); 5765 temp.back() = clearBuf();
5726 } 5766 }
5767 if (arg.assignment) {
5768 auto names = getArgDestructureList(arg.assignment);
5769 for (const auto& name : names) {
5770 forceAddToScope(name);
5771 }
5772 temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nll(def));
5773 transformAssignment(arg.assignment, temp);
5774 }
5727 if (varNames.empty()) 5775 if (varNames.empty())
5728 varNames = arg.name; 5776 varNames = arg.name;
5729 else 5777 else
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 1942e23..01ca083 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -893,7 +893,7 @@ YueParser::YueParser() {
893 893
894 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); 894 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line);
895 895
896 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp); 896 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable;
897 897
898 FnArgDefList = Seperator >> ( 898 FnArgDefList = Seperator >> (
899 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name)) | 899 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name)) |