diff options
| author | Li Jin <dragon-fly@qq.com> | 2025-08-26 12:50:50 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2025-08-26 12:50:50 +0800 |
| commit | d90857cc05cd0820a2057c547e95b02d24d15412 (patch) | |
| tree | 7cd1fb7ecff4799140eb96d5c3d7f48a3c76edc7 | |
| parent | 99692899d1e793e2cbbaea03107cb0a5f5e5c452 (diff) | |
| download | yuescript-d90857cc05cd0820a2057c547e95b02d24d15412.tar.gz yuescript-d90857cc05cd0820a2057c547e95b02d24d15412.tar.bz2 yuescript-d90857cc05cd0820a2057c547e95b02d24d15412.zip | |
Added function argument destructuring.
| -rw-r--r-- | spec/inputs/funcs.yue | 31 | ||||
| -rw-r--r-- | spec/outputs/funcs.lua | 153 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 2 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 54 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 2 |
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 | ||
| 196 | do | ||
| 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 | |||
| 196 | nil | 227 | nil |
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()) |
| 285 | end | 285 | end |
| 286 | local _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 | ||
| 296 | end | ||
| 297 | do | ||
| 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 | ||
| 438 | end | ||
| 286 | return nil | 439 | return 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) | |||
| 780 | AST_END(Export) | 780 | AST_END(Export) |
| 781 | 781 | ||
| 782 | AST_NODE(FnArgDef) | 782 | AST_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 | ||
| 81 | const std::string_view version = "0.29.3"sv; | 81 | const std::string_view version = "0.29.4"sv; |
| 82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
| 83 | 83 | ||
| 84 | class CompileError : public std::logic_error { | 84 | class 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)) | |
