1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 09:59:29 +00:00

Add destructuring assignement

This commit is contained in:
Étienne Fildadut 2020-01-15 20:42:27 +01:00
parent 851e9f89d6
commit 842536b561
10 changed files with 3823 additions and 2985 deletions

View file

@ -42,6 +42,8 @@ end)
a.child?:method?() -- safe navigation operator
local {hey, method} = a -- destructuring assignement
local odd = [ -- table comprehension
for i=1, 10 do
if i%2 == 0 then
@ -70,11 +72,11 @@ end
Candran is released under the MIT License (see ```LICENSE``` for details).
#### Quick setup
Install Candran automatically using LuaRocks: ```sudo luarocks install rockspec/candran-0.10.0-1.rockspec```.
Install Candran automatically using LuaRocks: ```sudo luarocks install rockspec/candran-0.11.0-1.rockspec```.
Or manually install LPegLabel (```luarocks install lpeglabel```, version 1.5 or above), download this repository and use Candran through the scripts in ```bin/``` or use it as a library with the self-contained ```candran.lua```.
You can optionally install lua-linenoise (```luarocks install linenoise```) for an improved REPL. The rockspec does not install linenoise by default.
You can optionally install lua-linenoise (```luarocks install linenoise```, version 0.9 or above) for an improved REPL. The rockspec will install linenoise by default.
You can register the Candran package searcher in your main Lua file (`require("candran").setup()`) and any subsequent `require` call in your project will automatically search for Candran modules.
@ -245,6 +247,33 @@ Values returned by the function will be inserted in the generated table in the o
The table generation function also have access to the `self` variable (and its alias `@`), which is the table which is being created, so you can set any of the table's field.
##### Destructuring assignement
```lua
t = { x = 1, y = 2, z = 3 }
{x, y, z} = t -- x, y, z = t.x, t.y, t.z
{x = o} = t -- o = t.x
{["x"] = o} = t -- o = t["x"]
-- Also works with local, let, for ... in, if with assignement, +=, etc.
local {x, y} = t
let {x, y} = t
for i, {x, y} in ipairs{t} do end
if {x, y} = t then end
{x} += t -- x = x + t.x
-- Works as expected with multiple assignement.
a, {x, y, z}, b = 1, t, 2
```
Destruturing assignement allows to quickly extract fields from a table into a variable.
This is done by replacing the variable name in any assignement with a table literal, where every item is the name of the field and assigned variable. It is possible to use a different field name than the variable name by naming the table item (`fieldName = var` or `[fieldExpression] = var`).
##### Safe navigation operators
```lua
a = nil

View file

@ -11,7 +11,7 @@
#import("lib.lua-parser.parser")
local candran = {
VERSION = "0.10.0"
VERSION = "0.11.0"
}
--- Default options.

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@ return function(code, ast, options)
local r = options.newline..string.rep(options.indentation, indentLevel)
if options.mapLines then
local sub = code:sub(lastInputPos)
local source, line = sub:sub(1, sub:find("\n")):match("%-%- (.-)%:(%d+)\n")
local source, line = sub:sub(1, sub:find("\n")):match(".*%-%- (.-)%:(%d+)\n")
if source and line then
lastSource = source
@ -42,15 +42,31 @@ return function(code, ast, options)
return newline()
end
--- Module management
local required = {} -- { ["module"] = true, ... }
local requireStr = ""
-- Add the module "mod" to the list of modules to require, and load its field "field" (or the whole module if nil) into the variable "name".
local function addRequire(mod, name, field)
if not required[mod] then
requireStr ..= "local "..options.variablePrefix..name..(" = require(%q)"):format(mod)..(field and "."..field or "")..options.newline
required[mod] = true
--- State stacks
-- Used for context-sensitive syntax.
local states = {
push = {}, -- push stack variable names
destructuring = {}, -- list of variable that need to be assigned from a destructure {id = "parent variable", "field1", "field2"...}
scope = {} -- list of variables defined in the current scope
}
-- Push a new value on top of the stack "name". Returns an empty string for chaining.
local function push(name, state)
table.insert(states[name], state)
return ""
end
-- Remove the value on top of the stack "name". Returns an empty string for chaining.
local function pop(name)
table.remove(states[name])
return ""
end
-- Set the value on top of the stack "name". Returns an empty string for chaining.
local function set(name, state)
states[name][#states[name]] = state
return ""
end
-- Returns the value on top of the stack "name".
local function peek(name)
return states[name][#states[name]]
end
--- Variable management
@ -59,6 +75,26 @@ return function(code, ast, options)
return options.variablePrefix..name
end
-- Returns the prefixed temporary variable name.
local function tmp()
local scope = peek("scope")
local var = "%s_%s":format(options.variablePrefix, #scope)
table.insert(scope, var)
return var
end
--- Module management
local required = {} -- { ["full require expression"] = true, ... }
local requireStr = ""
-- Add the module "mod" to the list of modules to require, and load its field "field" (or the whole module if nil) into the variable "name".
local function addRequire(mod, name, field)
local req = "require(%q)%s":format(mod, field and "."..field or "")
if not required[req] then
requireStr ..= "local %s = %s%s":format(var(name), req, options.newline)
required[req] = true
end
end
--- AST traversal helpers
local loop = { "While", "Repeat", "Fornum", "Forin", "WhileExpr", "RepeatExpr", "FornumExpr", "ForinExpr" } -- loops tags (can contain continue)
local func = { "Function", "TableCompr", "DoExpr", "WhileExpr", "RepeatExpr", "IfExpr", "FornumExpr", "ForinExpr" } -- function scope tags (can contain push)
@ -132,26 +168,6 @@ return function(code, ast, options)
return true
end
--- State stacks
-- Used for context-sensitive syntax.
local states = {
push = {} -- push stack variable names
}
-- Push a new value on top of the stack "name". Returns an empty string for chaining.
local function push(name, state)
table.insert(states[name], state)
return ""
end
-- Remove the value on top of the stack "name". Returns an empty string for chaining.
local function pop(name)
table.remove(states[name])
return ""
end
-- Returns the value on top of the stack "name".
local function peek(name)
return states[name][#states[name]]
end
--- Lua compiler
local tags
-- Recursively returns the compiled AST Lua code, set "forceTag" to override the tag type and pass additional arguments to the tag constructor if needed.
@ -175,6 +191,43 @@ return function(code, ast, options)
local CONTINUE_STOP = () -- at the start of loops using continue
return unindent().."end"..newline().."::"..var"continue".."::"
end
local DESTRUCTURING_ASSIGN = (destructured, newlineAfter=false, noLocal=false) -- to define values from a destructuring assignement
local vars = {}
local values = {}
for _, list in ipairs(destructured) do
for _, v in ipairs(list) do
local var, val
if v.tag == "Id" then
var = v
val = { tag = "Index", { tag = "Id", list.id }, { tag = "String", v[1] } }
elseif v.tag == "Pair" then
var = v[2]
val = { tag = "Index", { tag = "Id", list.id }, v[1] }
else
error("unknown destructuring element type: "..tostring(v.tag))
end
if destructured.rightOp and destructured.leftOp then
val = { tag = "Op", destructured.rightOp, var, { tag = "Op", destructured.leftOp, val, var } }
elseif destructured.rightOp then
val = { tag = "Op", destructured.rightOp, var, val }
elseif destructured.leftOp then
val = { tag = "Op", destructured.leftOp, val, var }
end
table.insert(vars, lua(var))
table.insert(values, lua(val))
end
end
if #vars > 0 then
local decl = noLocal and "" or "local "
if newlineAfter then
return decl..table.concat(vars, ", ").." = "..table.concat(values, ", ")..newline()
else
return newline()..decl..table.concat(vars, ", ").." = "..table.concat(values, ", ")
end
else
return ""
end
end
--- Tag constructors
tags = setmetatable({
@ -185,7 +238,7 @@ return function(code, ast, options)
hasPush.tag = "Return"
hasPush = false
end
local r = ""
local r = push("scope", {})
if hasPush then
r ..= push("push", var"push").."local "..var"push".." = {}"..newline()
end
@ -198,7 +251,7 @@ return function(code, ast, options)
if hasPush and (t[#t] and t[#t].tag ~= "Return") then -- add return only if needed
r ..= newline().."return "..UNPACK(var"push")..pop("push")
end
return r
return r..pop("scope")
end,
-- stat --
@ -209,28 +262,73 @@ return function(code, ast, options)
end,
-- Set{ {lhs+} (opid? = opid?)? {expr+} }
Set = (t)
if #t == 2 then
return lua(t[1], "_lhs").." = "..lua(t[2], "_lhs")
elseif #t == 3 then
return lua(t[1], "_lhs").." = "..lua(t[3], "_lhs")
-- extract vars and values
local expr = t[#t]
local vars, values = {}, {}
local destructuringVars, destructuringValues = {}, {}
for i, n in ipairs(t[1]) do
if n.tag == "DestructuringId" then
table.insert(destructuringVars, n)
table.insert(destructuringValues, expr[i])
else
table.insert(vars, n)
table.insert(values, expr[i])
end
end
--
if #t == 2 or #t == 3 then
local r = ""
if #vars > 0 then
r = lua(vars, "_lhs").." = "..lua(values, "_lhs")
end
if #destructuringVars > 0 then
local destructured = {}
r ..= "local "..push("destructuring", destructured)..lua(destructuringVars, "_lhs")..pop("destructuring").." = "..lua(destructuringValues, "_lhs")
return r..DESTRUCTURING_ASSIGN(destructured, nil, true)
end
return r
elseif #t == 4 then
if t[3] == "=" then
local r = lua(t[1], "_lhs").." = "..lua({ t[2], t[1][1], { tag = "Paren", t[4][1] } }, "Op")
for i=2, math.min(#t[4], #t[1]), 1 do
r ..= ", "..lua({ t[2], t[1][i], { tag = "Paren", t[4][i] } }, "Op")
local r = ""
if #vars > 0 then
r ..= lua(vars, "_lhs").." = "..lua({ t[2], vars[1], { tag = "Paren", values[1] } }, "Op")
for i=2, math.min(#t[4], #vars), 1 do
r ..= ", "..lua({ t[2], vars[i], { tag = "Paren", values[i] } }, "Op")
end
end
if #destructuringVars > 0 then
local destructured = { rightOp = t[2] }
r ..= "local "..push("destructuring", destructured)..lua(destructuringVars, "_lhs")..pop("destructuring").." = "..lua(destructuringValues, "_lhs")
return r..DESTRUCTURING_ASSIGN(destructured, nil, true)
end
return r
else
local r = lua(t[1], "_lhs").." = "..lua({ t[3], { tag = "Paren", t[4][1] }, t[1][1] }, "Op")
local r = ""
if #vars > 0 then
r ..= lua(vars, "_lhs").." = "..lua({ t[3], { tag = "Paren", values[1] }, vars[1] }, "Op")
for i=2, math.min(#t[4], #t[1]), 1 do
r ..= ", "..lua({ t[3], { tag = "Paren", t[4][i] }, t[1][i] }, "Op")
r ..= ", "..lua({ t[3], { tag = "Paren", values[i] }, vars[i] }, "Op")
end
end
if #destructuringVars > 0 then
local destructured = { leftOp = t[3] }
r ..= "local "..push("destructuring", destructured)..lua(destructuringVars, "_lhs")..pop("destructuring").." = "..lua(destructuringValues, "_lhs")
return r..DESTRUCTURING_ASSIGN(destructured, nil, true)
end
return r
end
else -- You are mad.
local r = lua(t[1], "_lhs").." = "..lua({ t[2], t[1][1], { tag = "Op", t[4], { tag = "Paren", t[5][1] }, t[1][1] } }, "Op")
local r = ""
if #vars > 0 then
r ..= lua(vars, "_lhs").." = "..lua({ t[2], vars[1], { tag = "Op", t[4], { tag = "Paren", values[1] }, vars[1] } }, "Op")
for i=2, math.min(#t[5], #t[1]), 1 do
r ..= ", "..lua({ t[2], t[1][i], { tag = "Op", t[4], { tag = "Paren", t[5][i] }, t[1][i] } }, "Op")
r ..= ", "..lua({ t[2], vars[i], { tag = "Op", t[4], { tag = "Paren", values[i] }, vars[i] } }, "Op")
end
end
if #destructuringVars > 0 then
local destructured = { rightOp = t[2], leftOp = t[4] }
r ..= "local "..push("destructuring", destructured)..lua(destructuringVars, "_lhs")..pop("destructuring").." = "..lua(destructuringValues, "_lhs")
return r..DESTRUCTURING_ASSIGN(destructured, nil, true)
end
return r
end
@ -344,12 +442,13 @@ return function(code, ast, options)
end,
-- Forin{ {ident+} {expr+} block }
Forin = (t)
local destructured = {}
local hasContinue = any(t[3], { "Continue" }, loop)
local r = "for "..lua(t[1], "_lhs").." in "..lua(t[2], "_lhs").." do"..indent()
local r = "for "..push("destructuring", destructured)..lua(t[1], "_lhs")..pop("destructuring").." in "..lua(t[2], "_lhs").." do"..indent()
if hasContinue then
r ..= CONTINUE_START()
end
r ..= lua(t[3])
r ..= DESTRUCTURING_ASSIGN(destructured, true)..lua(t[3])
if hasContinue then
r ..= CONTINUE_STOP()
end
@ -357,15 +456,17 @@ return function(code, ast, options)
end,
-- Local{ {ident+} {expr+}? }
Local = (t)
local r = "local "..lua(t[1], "_lhs")
local destructured = {}
local r = "local "..push("destructuring", destructured)..lua(t[1], "_lhs")..pop("destructuring")
if t[2][1] then
r ..= " = "..lua(t[2], "_lhs")
end
return r
return r..DESTRUCTURING_ASSIGN(destructured)
end,
-- Let{ {ident+} {expr+}? }
Let = (t)
local nameList = lua(t[1], "_lhs")
local destructured = {}
local nameList = push("destructuring", destructured)..lua(t[1], "_lhs")..pop("destructuring")
local r = "local "..nameList
if t[2][1] then
if all(t[2], { "Nil", "Dots", "Boolean", "Number", "String" }) then -- predeclaration doesn't matter here
@ -374,7 +475,7 @@ return function(code, ast, options)
r ..= newline()..nameList.." = "..lua(t[2], "_lhs")
end
end
return r
return r..DESTRUCTURING_ASSIGN(destructured)
end,
-- Localrec{ {ident} {expr} }
Localrec = (t)
@ -658,6 +759,21 @@ return function(code, ast, options)
Id = (t)
return t[1]
end,
-- DestructuringId{ Id | Pair+ }
DestructuringId = (t)
if t.id then -- destructing already done before, use parent variable as id
return t.id
else
local d = assert(peek("destructuring"), "DestructuringId not in a destructurable assignement")
local vars = { id = tmp() }
for j=1, #t, 1 do
table.insert(vars, t[j])
end
table.insert(d, vars)
t.id = vars.id
return vars.id
end
end,
-- Index{ expr expr }
Index = (t)
if t[1].tag == "String" or t[1].tag == "Table" then

View file

@ -1,4 +1,4 @@
targetName = "luajit"
targetName = "LuaJIT"
UNPACK = (list, i, j)
return "unpack(" .. list .. (i and (", " .. i .. (j and (", " .. j) or "")) or "") .. ")"

View file

@ -6,7 +6,7 @@ To be implemented, theese need to:
* are invalid vanilla Lua syntax.
* are not ambigous with any vanilla Lua syntax.
* be significantly useful compared to existing Candran/Lua code.
* be useful without having to rewrite APIs specifically for Candran. Candran intends to make Lua easier, not supersede it.
* be useful without having to rewrite APIs specifically for Candran. Candran intends to make Lua easier, not replace it.
Example rejected ideas:
* Python-style function decorators (implemented in Candran 0.1.0):
@ -37,6 +37,7 @@ end
local a = new Thing()
->
(TODO: define how classes work. May even use ClassCommons)
Not very Lua-ey to impose how to make your classes?
* try / except|catch / finally / else / other keywords
@ -48,6 +49,8 @@ finally
clean()
end
may be doable using if with assignement + pcall
* static type checking
local a = externalFunc() -- unknown
if a == "hey" then
@ -70,20 +73,26 @@ local b = a[3:5:1]
is it actually useful? even in python I rarely use it, apart from extracting a row or column for a matrix (and we don't have >1D arrays in Lua so...)
OR return multiple value instead of a list?
or list of incices:
local a, b, c = l[1, 2, 3]
how to handle hash table?
local a, b, c = l.(a, b, c)
or
local a, b, c = l.a, .b, .c
but
local a, b, c = l[1], [2], [3]
conflicts with table comprehension: change or use .[n]?
or create some syntax akin to destructuring assignemnts but for numeric indexes:
local [a, b, c] = t
* Destructuring assignment
local pos = { x = 5, y = 12 }
local {x, y} = pos -- x, y = pos.x, pos.y
local {a, b, x = x, y = y} = pos -- x, y = pos.x, pos.y, a = pos[1], b = pos[2]
local {a, b, :x, :y} = pos -- shorthand for the above line. Or .x, .y
local {:x.u} = pos OR {:x:u} OR {.x.u} -- u = pos.x.u
local [x, y] = pos -- x, y = pos[0], pos[1]
local x, y $= pos
And in implicit assignments:
for i, {x, y} in ipairs(positions) do
Sounds useful, at least the key-value part.
Allow recursive destructing assignements
* String interpolation
Delimited by ``:
@ -93,4 +102,7 @@ Also allows multi-line with this maybe?
meh
* Other potential inspiration
https://www.ruby-lang.org/fr/
https://www.ruby-lang.org/
* Lua 5.4 stuff
const, to-be-closed variables: they're fun but as of now the syntax is awful

View file

@ -59,7 +59,7 @@ apply:
`Call{ expr expr* }
| `SafeCall{ expr expr* }
lhs: `Id{ <string> } | `Index{ expr expr }
lhs: `Id{ <string> } | `Index{ expr expr } | ˇDestructuringId{ Id | Pair+ }
opid: -- includes additional operators from Lua 5.3 and all relational operators
'add' | 'sub' | 'mul' | 'div'
@ -164,6 +164,10 @@ local labels = {
{ "ErrExprFKey", "expected an expression after '[' for the table key" },
{ "ErrCBracketFKey", "expected ']' to close the table key" },
{ "ErrCBraceDestructuring", "expected '}' to close the destructuring variable list" },
{ "ErrDestructuringEqField", "expected '=' after the table key in destructuring variable list" },
{ "ErrDestructuringExprField", "expected an identifier after '=' in destructuring variable list" },
{ "ErrCBracketTableCompr", "expected ']' to close the table comprehension" },
{ "ErrDigitHex", "expected one or more hexadecimal digits after '0x'" },
@ -480,8 +484,9 @@ local G = { V"Lua",
Block = tagC("Block", (V"Stat" + -V"BlockEnd" * throw("InvalidStat"))^0 * ((V"RetStat" + V"ImplicitPushStat") * sym(";")^-1)^-1);
Stat = V"IfStat" + V"DoStat" + V"WhileStat" + V"RepeatStat" + V"ForStat"
+ V"LocalStat" + V"FuncStat" + V"BreakStat" + V"LabelStat" + V"GoToStat"
+ V"LetStat"
+ V"FuncCall" + V"Assignment"
+ V"LetStat" + V"ContinueStat" + V"PushStat"
+ V"ContinueStat" + V"PushStat"
+ sym(";");
BlockEnd = P"return" + "end" + "elseif" + "else" + "until" + "]" + -1 + V"ImplicitPushStat" + V"Assignment";
@ -502,17 +507,19 @@ local G = { V"Lua",
ForNum = tagC("Fornum", V"Id" * sym("=") * V"NumRange" * V"ForBody");
NumRange = expect(V"Expr", "ExprFor1") * expect(sym(","), "CommaFor") *expect(V"Expr", "ExprFor2")
* (sym(",") * expect(V"Expr", "ExprFor3"))^-1;
ForIn = tagC("Forin", V"NameList" * expect(kw("in"), "InFor") * expect(V"ExprList", "EListFor") * V"ForBody");
ForIn = tagC("Forin", V"DestructuringNameList" * expect(kw("in"), "InFor") * expect(V"ExprList", "EListFor") * V"ForBody");
ForBody = expectBlockOrSingleStatWithStartEnd(kw("do"), "DoFor", "EndFor");
LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal");
LocalFunc = tagC("Localrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat;
LocalAssign = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())));
LocalAssign = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())))
+ tagC("Local", V"DestructuringNameList" * sym("=") * expect(V"ExprList", "EListLAssign"));
LetStat = kw("let") * expect(V"LetAssign", "DefLet");
LetAssign = tagC("Let", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())));
LetAssign = tagC("Let", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())))
+ tagC("Let", V"DestructuringNameList" * sym("=") * expect(V"ExprList", "EListLAssign"));
Assignment = tagC("Set", V"VarList" * V"BinOp"^-1 * (P"=" / "=") * ((V"BinOp" - P"-") + #(P"-" * V"Space") * V"BinOp")^-1 * V"Skip" * expect(V"ExprList", "EListAssign"));
Assignment = tagC("Set", (V"VarList" + V"DestructuringNameList") * V"BinOp"^-1 * (P"=" / "=") * ((V"BinOp" - P"-") + #(P"-" * V"Space") * V"BinOp")^-1 * V"Skip" * expect(V"ExprList", "EListAssign"));
FuncStat = tagC("Set", kw("function") * expect(V"FuncName", "FuncName") * V"FuncBody") / fixFuncStat;
FuncName = Cf(V"Id" * (sym(".") * expect(V"StrId", "NameFunc1"))^0, insertIndex)
@ -541,9 +548,15 @@ local G = { V"Lua",
ImplicitPushStat = tagC("Push", commaSep(V"Expr", "RetList"));
NameList = tagC("NameList", commaSep(V"Id"));
DestructuringNameList = tagC("NameList", commaSep(V"DestructuringId")),
VarList = tagC("VarList", commaSep(V"VarExpr"));
ExprList = tagC("ExpList", commaSep(V"Expr", "ExprList"));
DestructuringId = tagC("DestructuringId", sym("{") * V"DestructuringIdFieldList" * expect(sym("}"), "CBraceDestructuring")) + V"Id",
DestructuringIdFieldList = sepBy(V"DestructuringIdField", V"FieldSep") * V"FieldSep"^-1;
DestructuringIdField = tagC("Pair", V"FieldKey" * expect(sym("="), "DestructuringEqField") * expect(V"Id", "DestructuringExprField"))
+ V"Id";
Expr = V"OrExpr";
OrExpr = chainOp(V"AndExpr", V"OrOp", "OrExpr");
AndExpr = chainOp(V"RelExpr", V"AndOp", "AndExpr");
@ -564,7 +577,7 @@ local G = { V"Lua",
+ tagC("Boolean", kw("true") * Cc(true))
+ tagC("Dots", sym("..."))
+ V"FuncDef"
+ (when("lexpr") * tagC("LetExpr", V"NameList" * sym("=") * -sym("=") * expect(V"ExprList", "EListLAssign")))
+ (when("lexpr") * tagC("LetExpr", V"DestructuringNameList" * sym("=") * -sym("=") * expect(V"ExprList", "EListLAssign")))
+ V"ShortFuncDef"
+ V"SuffixedExpr"
+ V"StatExpr";

View file

@ -304,6 +304,8 @@ function traverse_var (env, var)
status, msg = traverse_exp(env, var[2])
if not status then return status, msg end
return true
elseif tag == "DestructuringId" then
return traverse_table(env, var)
else
error("expecting a variable, but got a " .. tag)
end

View file

@ -19,12 +19,13 @@ description = {
source = {
url = "git://github.com/Reuh/candran",
tag = "v0.10.0"
tag = "v0.11.0"
}
dependencies = {
"lua >= 5.1",
"lpeglabel >= 1.5.0"
"lpeglabel >= 1.5.0",
"linenoise >= 0.9"
}
build = {

View file

@ -10,6 +10,10 @@ local function test(name, candranCode, expectedResult, options)
results[name] = { result = "not finished", message = "no info" }
local self = results[name]
-- options
options = options or {}
options.chunkname = name
-- make code
local success, code = pcall(candran.make, candranCode, options)
if not success then
@ -823,6 +827,187 @@ test("safe prefixes, random chaining", [[
assert(f.l?:o?() == nil)
]])
-- Destructuring assigments
test("destructuring assignement with an expression", [[
local {x, y} = { x = 5, y = 1 }
return x + y
]], 6)
test("destructuring assignement with local", [[
t = { x = 5, y = 1 }
local {x, y} = t
return x + y
]], 6)
test("destructuring assignement", [[
t = { x = 5, y = 1 }
{x, y} = t
return x + y
]], 6)
test("destructuring assignement with +=", [[
t = { x = 5, y = 1 }
local x, y = 5, 9
{x, y} += t
return x + y
]], 20)
test("destructuring assignement with =-", [[
t = { x = 5, y = 1 }
local x, y = 5, 9
{x, y} =- t
return x + y
]], -8)
test("destructuring assignement with +=-", [[
t = { x = 5, y = 1 }
local x, y = 5, 9
{x, y} +=- t
return x + y
]], 6)
test("destructuring assignement with =-", [[
t = { x = 5, y = 1 }
local x, y = 5, 9
{x, y} =- t
return x + y
]], -8)
test("destructuring assignement with let", [[
t = { x = 5, y = 1 }
let {x, y} = t
return x + y
]], 6)
test("destructuring assignement with for in", [[
t = {{ x = 5, y = 1 }}
for k, {x, y} in pairs(t) do
return x + y
end
]], 6)
test("destructuring assignement with if with assignement", [[
t = { x = 5, y = 1 }
if {x, y} = t then
return x + y
end
]], 6)
test("destructuring assignement with if-elseif with assignement", [[
t = { x = 5, y = 1 }
if ({u} = t) and u then
return 0
elseif {x, y} = t then
return x + y
end
]], 6)
test("destructuring assignement with an expression with custom name", [[
local {o = x, y} = { o = 5, y = 1 }
return x + y
]], 6)
test("destructuring assignement with local with custom name", [[
t = { o = 5, y = 1 }
local {o = x, y} = t
return x + y
]], 6)
test("destructuring assignement with custom name", [[
t = { o = 5, y = 1 }
{o = x, y} = t
return x + y
]], 6)
test("destructuring assignement with += with custom name", [[
t = { o = 5, y = 1 }
local x, y = 5, 9
{o = x, y} += t
return x + y
]], 20)
test("destructuring assignement with =- with custom name", [[
t = { o = 5, y = 1 }
local x, y = 5, 9
{o = x, y} =- t
return x + y
]], -8)
test("destructuring assignement with +=- with custom name", [[
t = { o = 5, y = 1 }
local x, y = 5, 9
{o = x, y} +=- t
return x + y
]], 6)
test("destructuring assignement with let with custom name", [[
t = { o = 5, y = 1 }
let {o = x, y} = t
return x + y
]], 6)
test("destructuring assignement with for in with custom name", [[
t = {{ o = 5, y = 1 }}
for k, {o = x, y} in pairs(t) do
return x + y
end
]], 6)
test("destructuring assignement with if with assignement with custom name", [[
t = { o = 5, y = 1 }
if {o = x, y} = t then
return x + y
end
]], 6)
test("destructuring assignement with if-elseif with assignement with custom name", [[
t = { o = 5, y = 1 }
if ({x} = t) and x then
return 0
elseif {o = x, y} = t then
return x + y
end
]], 6)
test("destructuring assignement with an expression with expression as key", [[
local {[1] = x, y} = { 5, y = 1 }
return x + y
]], 6)
test("destructuring assignement with local with expression as key", [[
t = { 5, y = 1 }
local {[1] = x, y} = t
return x + y
]], 6)
test("destructuring assignement with expression as key", [[
t = { 5, y = 1 }
{[1] = x, y} = t
return x + y
]], 6)
test("destructuring assignement with += with expression as key", [[
t = { 5, y = 1 }
local x, y = 5, 9
{[1] = x, y} += t
return x + y
]], 20)
test("destructuring assignement with =- with expression as key", [[
t = { 5, y = 1 }
local x, y = 5, 9
{[1] = x, y} =- t
return x + y
]], -8)
test("destructuring assignement with +=- with expression as key", [[
t = { 5, y = 1 }
local x, y = 5, 9
{[1] = x, y} +=- t
return x + y
]], 6)
test("destructuring assignement with let with expression as key", [[
t = { 5, y = 1 }
let {[1] = x, y} = t
return x + y
]], 6)
test("destructuring assignement with for in with expression as key", [[
t = {{ 5, y = 1 }}
for k, {[1] = x, y} in pairs(t) do
return x + y
end
]], 6)
test("destructuring assignement with if with assignement with expression as key", [[
t = { 5, y = 1 }
if {[1] = x, y} = t then
return x + y
end
]], 6)
test("destructuring assignement with if-elseif with assignement with expression as key", [[
t = { 5, y = 1 }
if ({x} = t) and x then
return 0
elseif {[1] = x, y} = t then
return x + y
end
]], 6)
-- results
local resultCounter = {}
local testCounter = 0