Yuescript
Yuescript copied to clipboard
[feature request] Implementing '...' for Variable Declaration within Scope using Anonymous Functions
Hi,
In the Lua language, the ellipsis ... can only be used in the last function argument.
local function a(...)
print(...)
end
It is not possible to declare it in the scope (e.g., as local ... = 1, 2).
local ok, ... = true, true -- syntax error! ('<name>' expected near '...')
My suggestion is to implement the use of ... to declare it in the scope, using anonymous functions for that purpose. During parsing, if there is ... in the variable declaration, Yuescript can wrap that scope inside a function and call it with the values. This way, ... will be defined within the same scope.
list = {1, 2, 3, 4, 5}
fn = (ok) ->
ok, table.unpack list
ok, ... = fn true
print ok, ...
ok, ...
compiles to:
local list = {
1,
2,
3,
4,
5
}
local fn
fn = function(ok)
return ok, table.unpack(list)
end
return (function(ok, ...)
print(ok, ...) -- "ok" and "..." is available here without errors!
return ok, ...
end)(fn(true))
Notes
In my scripts, I use varargs (...) returns frequently. Usually, they contain 'nil' (holes), so I cannot obtain the correct length if I wrap them in tables '{...}'. It is necessary to return the length and then use 'table.unpack'
local function fn_many_args()
return 10, nil, 20, nil, 30
end
local args = {fn_many_args()}
print(#args) --> 1
local _ = (function(...)
print(select("#", ...)) --> 5
print(...) --> 10, nil, 20, nil, 30
end)(fn_many_args())
-- I can pass the function to select:
print(select("#", fn_many_args())) --> 5
-- But, How can I get the items? I will need call the function twice!
print(select(1, fn_many_args())) --> 10, nil, 20, nil, 30
-- First to get length, and second to catch the items
Regards
Tried to add this feature, if you use vararg mutiple times in a same scope. You will get you're code block actually split in multiple anonymous functions.
list = {1, 2, 3, 4, 5}
fn = (ok) ->
ok, table.unpack list
ok, ... = fn true
print ok, ...
fn_many_args = ->
10, nil, 20, nil, 30
... = fn_many_args!
print select "#", ...
print ...
now compiles to:
local list = {
1,
2,
3,
4,
5
}
local fn
fn = function(ok)
return ok, table.unpack(list)
end
return (function(_arg_0, ...)
local ok = _arg_0
print(ok, ...)
local fn_many_args
fn_many_args = function()
return 10, nil, 20, nil, 30
end
return (function(...)
print(select("#", ...))
return print(...)
end)(fn_many_args())
end)(fn(true))
Thank you! Congratulations on the effort put into this project.
I found some inline expressions that don't compile or report errors:
... = 1, 2 if a
compiles to
return (function(...) end)(1, 2) -- 1
In this case, the inline expression should be placed within the anonymous function, or alternatively, report an error in inline expressions with varargs.
Fixed the behavior of varargs with inline expression to be the same as assignment statement with 33260af2175004347a3b9345b67727e596c6fffd.
a = 1 if true
... = 1, 2 if a
print ...
compiles to:
local a
if true then
a = 1
end
return (function(...)
return print(...)
end)((function()
if a then
return 1, 2
end
end)())
After running some tests, I realized that it's better if the compiler indicates an error when using all line decorators in varargs assignments.
It will print 2 when if true (ok), but it will print nil when if false (expected output was 1).
a = 1
a, ... = 2, ... if true
print a --> 2 (ok)
a = 1
a, ... = 2, ... if false
print a --> nil (1?)
I believe that if a line decorator is used in a vararg assignment, an error should be displayed because vararg assignment modifies the scope, and an explicit scoped if assignment makes more sense.
I agree with you for raising errors when using vararg assignment with line decorator. There is no way to tell the difference between:
a = 1
cond = false
value = 2
a, ... = value, ... if cond
print a --> expecting 1
a = 1
cond = true
value = nil
a, ... = value, ... if cond
print a --> expecting nil
So just raising error should be the best idea. Got this fixed until commit b0c461305cfc0dd1cf8235197224130a9bd78d68.