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:
parent
851e9f89d6
commit
842536b561
10 changed files with 3823 additions and 2985 deletions
33
README.md
33
README.md
|
|
@ -42,6 +42,8 @@ end)
|
||||||
|
|
||||||
a.child?:method?() -- safe navigation operator
|
a.child?:method?() -- safe navigation operator
|
||||||
|
|
||||||
|
local {hey, method} = a -- destructuring assignement
|
||||||
|
|
||||||
local odd = [ -- table comprehension
|
local odd = [ -- table comprehension
|
||||||
for i=1, 10 do
|
for i=1, 10 do
|
||||||
if i%2 == 0 then
|
if i%2 == 0 then
|
||||||
|
|
@ -70,11 +72,11 @@ end
|
||||||
Candran is released under the MIT License (see ```LICENSE``` for details).
|
Candran is released under the MIT License (see ```LICENSE``` for details).
|
||||||
|
|
||||||
#### Quick setup
|
#### 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```.
|
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.
|
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.
|
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
|
##### Safe navigation operators
|
||||||
```lua
|
```lua
|
||||||
a = nil
|
a = nil
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
#import("lib.lua-parser.parser")
|
#import("lib.lua-parser.parser")
|
||||||
|
|
||||||
local candran = {
|
local candran = {
|
||||||
VERSION = "0.10.0"
|
VERSION = "0.11.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Default options.
|
--- Default options.
|
||||||
|
|
|
||||||
5562
candran.lua
5562
candran.lua
File diff suppressed because it is too large
Load diff
|
|
@ -14,7 +14,7 @@ return function(code, ast, options)
|
||||||
local r = options.newline..string.rep(options.indentation, indentLevel)
|
local r = options.newline..string.rep(options.indentation, indentLevel)
|
||||||
if options.mapLines then
|
if options.mapLines then
|
||||||
local sub = code:sub(lastInputPos)
|
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
|
if source and line then
|
||||||
lastSource = source
|
lastSource = source
|
||||||
|
|
@ -42,15 +42,31 @@ return function(code, ast, options)
|
||||||
return newline()
|
return newline()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Module management
|
--- State stacks
|
||||||
local required = {} -- { ["module"] = true, ... }
|
-- Used for context-sensitive syntax.
|
||||||
local requireStr = ""
|
local states = {
|
||||||
-- 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".
|
push = {}, -- push stack variable names
|
||||||
local function addRequire(mod, name, field)
|
destructuring = {}, -- list of variable that need to be assigned from a destructure {id = "parent variable", "field1", "field2"...}
|
||||||
if not required[mod] then
|
scope = {} -- list of variables defined in the current scope
|
||||||
requireStr ..= "local "..options.variablePrefix..name..(" = require(%q)"):format(mod)..(field and "."..field or "")..options.newline
|
}
|
||||||
required[mod] = true
|
-- 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
|
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
|
end
|
||||||
|
|
||||||
--- Variable management
|
--- Variable management
|
||||||
|
|
@ -59,6 +75,26 @@ return function(code, ast, options)
|
||||||
return options.variablePrefix..name
|
return options.variablePrefix..name
|
||||||
end
|
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
|
--- AST traversal helpers
|
||||||
local loop = { "While", "Repeat", "Fornum", "Forin", "WhileExpr", "RepeatExpr", "FornumExpr", "ForinExpr" } -- loops tags (can contain continue)
|
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)
|
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
|
return true
|
||||||
end
|
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
|
--- Lua compiler
|
||||||
local tags
|
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.
|
-- 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
|
local CONTINUE_STOP = () -- at the start of loops using continue
|
||||||
return unindent().."end"..newline().."::"..var"continue".."::"
|
return unindent().."end"..newline().."::"..var"continue".."::"
|
||||||
end
|
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
|
--- Tag constructors
|
||||||
tags = setmetatable({
|
tags = setmetatable({
|
||||||
|
|
@ -185,7 +238,7 @@ return function(code, ast, options)
|
||||||
hasPush.tag = "Return"
|
hasPush.tag = "Return"
|
||||||
hasPush = false
|
hasPush = false
|
||||||
end
|
end
|
||||||
local r = ""
|
local r = push("scope", {})
|
||||||
if hasPush then
|
if hasPush then
|
||||||
r ..= push("push", var"push").."local "..var"push".." = {}"..newline()
|
r ..= push("push", var"push").."local "..var"push".." = {}"..newline()
|
||||||
end
|
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
|
if hasPush and (t[#t] and t[#t].tag ~= "Return") then -- add return only if needed
|
||||||
r ..= newline().."return "..UNPACK(var"push")..pop("push")
|
r ..= newline().."return "..UNPACK(var"push")..pop("push")
|
||||||
end
|
end
|
||||||
return r
|
return r..pop("scope")
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- stat --
|
-- stat --
|
||||||
|
|
@ -209,28 +262,73 @@ return function(code, ast, options)
|
||||||
end,
|
end,
|
||||||
-- Set{ {lhs+} (opid? = opid?)? {expr+} }
|
-- Set{ {lhs+} (opid? = opid?)? {expr+} }
|
||||||
Set = (t)
|
Set = (t)
|
||||||
if #t == 2 then
|
-- extract vars and values
|
||||||
return lua(t[1], "_lhs").." = "..lua(t[2], "_lhs")
|
local expr = t[#t]
|
||||||
elseif #t == 3 then
|
local vars, values = {}, {}
|
||||||
return lua(t[1], "_lhs").." = "..lua(t[3], "_lhs")
|
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
|
elseif #t == 4 then
|
||||||
if t[3] == "=" then
|
if t[3] == "=" then
|
||||||
local r = lua(t[1], "_lhs").." = "..lua({ t[2], t[1][1], { tag = "Paren", t[4][1] } }, "Op")
|
local r = ""
|
||||||
for i=2, math.min(#t[4], #t[1]), 1 do
|
if #vars > 0 then
|
||||||
r ..= ", "..lua({ t[2], t[1][i], { tag = "Paren", t[4][i] } }, "Op")
|
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
|
end
|
||||||
return r
|
return r
|
||||||
else
|
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
|
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
|
end
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
else -- You are mad.
|
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
|
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
|
end
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
@ -344,12 +442,13 @@ return function(code, ast, options)
|
||||||
end,
|
end,
|
||||||
-- Forin{ {ident+} {expr+} block }
|
-- Forin{ {ident+} {expr+} block }
|
||||||
Forin = (t)
|
Forin = (t)
|
||||||
|
local destructured = {}
|
||||||
local hasContinue = any(t[3], { "Continue" }, loop)
|
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
|
if hasContinue then
|
||||||
r ..= CONTINUE_START()
|
r ..= CONTINUE_START()
|
||||||
end
|
end
|
||||||
r ..= lua(t[3])
|
r ..= DESTRUCTURING_ASSIGN(destructured, true)..lua(t[3])
|
||||||
if hasContinue then
|
if hasContinue then
|
||||||
r ..= CONTINUE_STOP()
|
r ..= CONTINUE_STOP()
|
||||||
end
|
end
|
||||||
|
|
@ -357,15 +456,17 @@ return function(code, ast, options)
|
||||||
end,
|
end,
|
||||||
-- Local{ {ident+} {expr+}? }
|
-- Local{ {ident+} {expr+}? }
|
||||||
Local = (t)
|
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
|
if t[2][1] then
|
||||||
r ..= " = "..lua(t[2], "_lhs")
|
r ..= " = "..lua(t[2], "_lhs")
|
||||||
end
|
end
|
||||||
return r
|
return r..DESTRUCTURING_ASSIGN(destructured)
|
||||||
end,
|
end,
|
||||||
-- Let{ {ident+} {expr+}? }
|
-- Let{ {ident+} {expr+}? }
|
||||||
Let = (t)
|
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
|
local r = "local "..nameList
|
||||||
if t[2][1] then
|
if t[2][1] then
|
||||||
if all(t[2], { "Nil", "Dots", "Boolean", "Number", "String" }) then -- predeclaration doesn't matter here
|
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")
|
r ..= newline()..nameList.." = "..lua(t[2], "_lhs")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return r
|
return r..DESTRUCTURING_ASSIGN(destructured)
|
||||||
end,
|
end,
|
||||||
-- Localrec{ {ident} {expr} }
|
-- Localrec{ {ident} {expr} }
|
||||||
Localrec = (t)
|
Localrec = (t)
|
||||||
|
|
@ -658,6 +759,21 @@ return function(code, ast, options)
|
||||||
Id = (t)
|
Id = (t)
|
||||||
return t[1]
|
return t[1]
|
||||||
end,
|
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{ expr expr }
|
||||||
Index = (t)
|
Index = (t)
|
||||||
if t[1].tag == "String" or t[1].tag == "Table" then
|
if t[1].tag == "String" or t[1].tag == "Table" then
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
targetName = "luajit"
|
targetName = "LuaJIT"
|
||||||
|
|
||||||
UNPACK = (list, i, j)
|
UNPACK = (list, i, j)
|
||||||
return "unpack(" .. list .. (i and (", " .. i .. (j and (", " .. j) or "")) or "") .. ")"
|
return "unpack(" .. list .. (i and (", " .. i .. (j and (", " .. j) or "")) or "") .. ")"
|
||||||
|
|
|
||||||
40
ideas.txt
40
ideas.txt
|
|
@ -6,7 +6,7 @@ To be implemented, theese need to:
|
||||||
* are invalid vanilla Lua syntax.
|
* are invalid vanilla Lua syntax.
|
||||||
* are not ambigous with any vanilla Lua syntax.
|
* are not ambigous with any vanilla Lua syntax.
|
||||||
* be significantly useful compared to existing Candran/Lua code.
|
* 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:
|
Example rejected ideas:
|
||||||
* Python-style function decorators (implemented in Candran 0.1.0):
|
* Python-style function decorators (implemented in Candran 0.1.0):
|
||||||
|
|
@ -37,6 +37,7 @@ end
|
||||||
local a = new Thing()
|
local a = new Thing()
|
||||||
->
|
->
|
||||||
(TODO: define how classes work. May even use ClassCommons)
|
(TODO: define how classes work. May even use ClassCommons)
|
||||||
|
|
||||||
Not very Lua-ey to impose how to make your classes?
|
Not very Lua-ey to impose how to make your classes?
|
||||||
|
|
||||||
* try / except|catch / finally / else / other keywords
|
* try / except|catch / finally / else / other keywords
|
||||||
|
|
@ -48,6 +49,8 @@ finally
|
||||||
clean()
|
clean()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
may be doable using if with assignement + pcall
|
||||||
|
|
||||||
* static type checking
|
* static type checking
|
||||||
local a = externalFunc() -- unknown
|
local a = externalFunc() -- unknown
|
||||||
if a == "hey" then
|
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...)
|
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
|
* Destructuring assignment
|
||||||
local pos = { x = 5, y = 12 }
|
|
||||||
|
|
||||||
local {x, y} = pos -- x, y = pos.x, pos.y
|
Allow recursive destructing assignements
|
||||||
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.
|
|
||||||
|
|
||||||
* String interpolation
|
* String interpolation
|
||||||
Delimited by ``:
|
Delimited by ``:
|
||||||
|
|
@ -93,4 +102,7 @@ Also allows multi-line with this maybe?
|
||||||
meh
|
meh
|
||||||
|
|
||||||
* Other potential inspiration
|
* 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
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ apply:
|
||||||
`Call{ expr expr* }
|
`Call{ expr expr* }
|
||||||
| `SafeCall{ 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
|
opid: -- includes additional operators from Lua 5.3 and all relational operators
|
||||||
'add' | 'sub' | 'mul' | 'div'
|
'add' | 'sub' | 'mul' | 'div'
|
||||||
|
|
@ -164,6 +164,10 @@ local labels = {
|
||||||
{ "ErrExprFKey", "expected an expression after '[' for the table key" },
|
{ "ErrExprFKey", "expected an expression after '[' for the table key" },
|
||||||
{ "ErrCBracketFKey", "expected ']' to close 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" },
|
{ "ErrCBracketTableCompr", "expected ']' to close the table comprehension" },
|
||||||
|
|
||||||
{ "ErrDigitHex", "expected one or more hexadecimal digits after '0x'" },
|
{ "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);
|
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"
|
Stat = V"IfStat" + V"DoStat" + V"WhileStat" + V"RepeatStat" + V"ForStat"
|
||||||
+ V"LocalStat" + V"FuncStat" + V"BreakStat" + V"LabelStat" + V"GoToStat"
|
+ V"LocalStat" + V"FuncStat" + V"BreakStat" + V"LabelStat" + V"GoToStat"
|
||||||
|
+ V"LetStat"
|
||||||
+ V"FuncCall" + V"Assignment"
|
+ V"FuncCall" + V"Assignment"
|
||||||
+ V"LetStat" + V"ContinueStat" + V"PushStat"
|
+ V"ContinueStat" + V"PushStat"
|
||||||
+ sym(";");
|
+ sym(";");
|
||||||
BlockEnd = P"return" + "end" + "elseif" + "else" + "until" + "]" + -1 + V"ImplicitPushStat" + V"Assignment";
|
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");
|
ForNum = tagC("Fornum", V"Id" * sym("=") * V"NumRange" * V"ForBody");
|
||||||
NumRange = expect(V"Expr", "ExprFor1") * expect(sym(","), "CommaFor") *expect(V"Expr", "ExprFor2")
|
NumRange = expect(V"Expr", "ExprFor1") * expect(sym(","), "CommaFor") *expect(V"Expr", "ExprFor2")
|
||||||
* (sym(",") * expect(V"Expr", "ExprFor3"))^-1;
|
* (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");
|
ForBody = expectBlockOrSingleStatWithStartEnd(kw("do"), "DoFor", "EndFor");
|
||||||
|
|
||||||
LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal");
|
LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal");
|
||||||
LocalFunc = tagC("Localrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat;
|
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");
|
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;
|
FuncStat = tagC("Set", kw("function") * expect(V"FuncName", "FuncName") * V"FuncBody") / fixFuncStat;
|
||||||
FuncName = Cf(V"Id" * (sym(".") * expect(V"StrId", "NameFunc1"))^0, insertIndex)
|
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"));
|
ImplicitPushStat = tagC("Push", commaSep(V"Expr", "RetList"));
|
||||||
|
|
||||||
NameList = tagC("NameList", commaSep(V"Id"));
|
NameList = tagC("NameList", commaSep(V"Id"));
|
||||||
|
DestructuringNameList = tagC("NameList", commaSep(V"DestructuringId")),
|
||||||
VarList = tagC("VarList", commaSep(V"VarExpr"));
|
VarList = tagC("VarList", commaSep(V"VarExpr"));
|
||||||
ExprList = tagC("ExpList", commaSep(V"Expr", "ExprList"));
|
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";
|
Expr = V"OrExpr";
|
||||||
OrExpr = chainOp(V"AndExpr", V"OrOp", "OrExpr");
|
OrExpr = chainOp(V"AndExpr", V"OrOp", "OrExpr");
|
||||||
AndExpr = chainOp(V"RelExpr", V"AndOp", "AndExpr");
|
AndExpr = chainOp(V"RelExpr", V"AndOp", "AndExpr");
|
||||||
|
|
@ -564,7 +577,7 @@ local G = { V"Lua",
|
||||||
+ tagC("Boolean", kw("true") * Cc(true))
|
+ tagC("Boolean", kw("true") * Cc(true))
|
||||||
+ tagC("Dots", sym("..."))
|
+ tagC("Dots", sym("..."))
|
||||||
+ V"FuncDef"
|
+ 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"ShortFuncDef"
|
||||||
+ V"SuffixedExpr"
|
+ V"SuffixedExpr"
|
||||||
+ V"StatExpr";
|
+ V"StatExpr";
|
||||||
|
|
|
||||||
|
|
@ -304,6 +304,8 @@ function traverse_var (env, var)
|
||||||
status, msg = traverse_exp(env, var[2])
|
status, msg = traverse_exp(env, var[2])
|
||||||
if not status then return status, msg end
|
if not status then return status, msg end
|
||||||
return true
|
return true
|
||||||
|
elseif tag == "DestructuringId" then
|
||||||
|
return traverse_table(env, var)
|
||||||
else
|
else
|
||||||
error("expecting a variable, but got a " .. tag)
|
error("expecting a variable, but got a " .. tag)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,13 @@ description = {
|
||||||
|
|
||||||
source = {
|
source = {
|
||||||
url = "git://github.com/Reuh/candran",
|
url = "git://github.com/Reuh/candran",
|
||||||
tag = "v0.10.0"
|
tag = "v0.11.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies = {
|
dependencies = {
|
||||||
"lua >= 5.1",
|
"lua >= 5.1",
|
||||||
"lpeglabel >= 1.5.0"
|
"lpeglabel >= 1.5.0",
|
||||||
|
"linenoise >= 0.9"
|
||||||
}
|
}
|
||||||
|
|
||||||
build = {
|
build = {
|
||||||
695
test/test.lua
695
test/test.lua
|
|
@ -10,6 +10,10 @@ local function test(name, candranCode, expectedResult, options)
|
||||||
results[name] = { result = "not finished", message = "no info" }
|
results[name] = { result = "not finished", message = "no info" }
|
||||||
local self = results[name]
|
local self = results[name]
|
||||||
|
|
||||||
|
-- options
|
||||||
|
options = options or {}
|
||||||
|
options.chunkname = name
|
||||||
|
|
||||||
-- make code
|
-- make code
|
||||||
local success, code = pcall(candran.make, candranCode, options)
|
local success, code = pcall(candran.make, candranCode, options)
|
||||||
if not success then
|
if not success then
|
||||||
|
|
@ -125,203 +129,203 @@ return a
|
||||||
|
|
||||||
-- Assignement operators
|
-- Assignement operators
|
||||||
test("+=", [[
|
test("+=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a += 2
|
a += 2
|
||||||
return a
|
return a
|
||||||
]], 7)
|
]], 7)
|
||||||
test("-=", [[
|
test("-=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a -= 2
|
a -= 2
|
||||||
return a
|
return a
|
||||||
]], 3)
|
]], 3)
|
||||||
test("*=", [[
|
test("*=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a *= 2
|
a *= 2
|
||||||
return a
|
return a
|
||||||
]], 10)
|
]], 10)
|
||||||
test("/=", [[
|
test("/=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a /= 2
|
a /= 2
|
||||||
return a
|
return a
|
||||||
]], 5/2)
|
]], 5/2)
|
||||||
test("//=", [[
|
test("//=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a //= 2
|
a //= 2
|
||||||
return a
|
return a
|
||||||
]], 2)
|
]], 2)
|
||||||
test("^=", [[
|
test("^=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a ^= 2
|
a ^= 2
|
||||||
return a
|
return a
|
||||||
]], 25)
|
]], 25)
|
||||||
test("%=", [[
|
test("%=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a %= 2
|
a %= 2
|
||||||
return a
|
return a
|
||||||
]], 5%2)
|
]], 5%2)
|
||||||
test("..=", [[
|
test("..=", [[
|
||||||
local a = "hello"
|
local a = "hello"
|
||||||
a ..= " world"
|
a ..= " world"
|
||||||
return a
|
return a
|
||||||
]], "hello world")
|
]], "hello world")
|
||||||
test("and=", [[
|
test("and=", [[
|
||||||
local a = true
|
local a = true
|
||||||
a and= "world"
|
a and= "world"
|
||||||
return a
|
return a
|
||||||
]], "world")
|
]], "world")
|
||||||
test("or=", [[
|
test("or=", [[
|
||||||
local a = false
|
local a = false
|
||||||
a or= "world"
|
a or= "world"
|
||||||
return a
|
return a
|
||||||
]], "world")
|
]], "world")
|
||||||
test("&=", [[
|
test("&=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a &= 3
|
a &= 3
|
||||||
return a
|
return a
|
||||||
]], 1)
|
]], 1)
|
||||||
test("|=", [[
|
test("|=", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a |= 3
|
a |= 3
|
||||||
return a
|
return a
|
||||||
]], 7)
|
]], 7)
|
||||||
test("<<=", [[
|
test("<<=", [[
|
||||||
local a = 23
|
local a = 23
|
||||||
a <<= 2
|
a <<= 2
|
||||||
return a
|
return a
|
||||||
]], 92)
|
]], 92)
|
||||||
test(">>=", [[
|
test(">>=", [[
|
||||||
local a = 23
|
local a = 23
|
||||||
a >>= 2
|
a >>= 2
|
||||||
return a
|
return a
|
||||||
]], 5)
|
]], 5)
|
||||||
|
|
||||||
test("right assigments operators", [[
|
test("right assigments operators", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a =+ 2 assert(a == 7, "=+")
|
a =+ 2 assert(a == 7, "=+")
|
||||||
a =- 2 assert(a == -5, "=-")
|
a =- 2 assert(a == -5, "=-")
|
||||||
a =* -2 assert(a == 10, "=*")
|
a =* -2 assert(a == 10, "=*")
|
||||||
a =/ 2 assert(a == 0.2, "=/")
|
a =/ 2 assert(a == 0.2, "=/")
|
||||||
a =// 2 assert(a == 10, "=//")
|
a =// 2 assert(a == 10, "=//")
|
||||||
a =^ 2 assert(a == 1024, "=^")
|
a =^ 2 assert(a == 1024, "=^")
|
||||||
a =% 2000 assert(a == 976, "=%")
|
a =% 2000 assert(a == 976, "=%")
|
||||||
|
|
||||||
a = "world"
|
a = "world"
|
||||||
a =.. "hello " assert(a == "hello world", "=..")
|
a =.. "hello " assert(a == "hello world", "=..")
|
||||||
a =and true assert(a == "hello world", "=and")
|
a =and true assert(a == "hello world", "=and")
|
||||||
|
|
||||||
a = false
|
a = false
|
||||||
a =or nil assert(a == false, "=or")
|
a =or nil assert(a == false, "=or")
|
||||||
|
|
||||||
a = 3
|
a = 3
|
||||||
a =& 5 assert(a == 1, '=&')
|
a =& 5 assert(a == 1, '=&')
|
||||||
a =| 20 assert(a == 21, "=|")
|
a =| 20 assert(a == 21, "=|")
|
||||||
a =<< 1 assert(a == 2097152, "=<<")
|
a =<< 1 assert(a == 2097152, "=<<")
|
||||||
|
|
||||||
a = 2
|
a = 2
|
||||||
a =>> 23 assert(a == 5, "=>>")
|
a =>> 23 assert(a == 5, "=>>")
|
||||||
]], nil)
|
]], nil)
|
||||||
|
|
||||||
test("some left+right assigments operators", [[
|
test("some left+right assigments operators", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a -=+ 2 assert(a == 8, "-=+")
|
a -=+ 2 assert(a == 8, "-=+")
|
||||||
|
|
||||||
a = "hello"
|
a = "hello"
|
||||||
a ..=.. " world " assert(a == "hello world hello", "..=..")
|
a ..=.. " world " assert(a == "hello world hello", "..=..")
|
||||||
]], nil)
|
]], nil)
|
||||||
|
|
||||||
test("left assigments operators priority", [[
|
test("left assigments operators priority", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a *= 2 + 3
|
a *= 2 + 3
|
||||||
return a
|
return a
|
||||||
]], 25)
|
]], 25)
|
||||||
test("right assigments operators priority", [[
|
test("right assigments operators priority", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a =/ 2 + 3
|
a =/ 2 + 3
|
||||||
return a
|
return a
|
||||||
]], 1)
|
]], 1)
|
||||||
test("left+right assigments operators priority", [[
|
test("left+right assigments operators priority", [[
|
||||||
local a = 5
|
local a = 5
|
||||||
a *=/ 2 + 3
|
a *=/ 2 + 3
|
||||||
return a
|
return a
|
||||||
]], 5)
|
]], 5)
|
||||||
|
|
||||||
-- Default function parameters
|
-- Default function parameters
|
||||||
test("default parameters", [[
|
test("default parameters", [[
|
||||||
local function test(hey, def="re", no, foo=("bar"):gsub("bar", "batru"))
|
local function test(hey, def="re", no, foo=("bar"):gsub("bar", "batru"))
|
||||||
return def..foo
|
return def..foo
|
||||||
end
|
end
|
||||||
return test(78, "SANDWICH", true)
|
return test(78, "SANDWICH", true)
|
||||||
]], "SANDWICHbatru")
|
]], "SANDWICHbatru")
|
||||||
|
|
||||||
-- @ self alias
|
-- @ self alias
|
||||||
test("@ as self alias", [[
|
test("@ as self alias", [[
|
||||||
local a = {}
|
local a = {}
|
||||||
function a:hey()
|
function a:hey()
|
||||||
return @ == self
|
return @ == self
|
||||||
end
|
end
|
||||||
return a:hey()
|
return a:hey()
|
||||||
]], true)
|
]], true)
|
||||||
test("@ as self alias and indexation", [[
|
test("@ as self alias and indexation", [[
|
||||||
local a = {
|
local a = {
|
||||||
foo = "Hoi"
|
foo = "Hoi"
|
||||||
}
|
}
|
||||||
function a:hey()
|
function a:hey()
|
||||||
return @.foo
|
return @.foo
|
||||||
end
|
end
|
||||||
return a:hey()
|
return a:hey()
|
||||||
]], "Hoi")
|
]], "Hoi")
|
||||||
test("@name indexation", [[
|
test("@name indexation", [[
|
||||||
local a = {
|
local a = {
|
||||||
foo = "Hoi"
|
foo = "Hoi"
|
||||||
}
|
}
|
||||||
function a:hey()
|
function a:hey()
|
||||||
return @foo
|
return @foo
|
||||||
end
|
end
|
||||||
return a:hey()
|
return a:hey()
|
||||||
]], "Hoi")
|
]], "Hoi")
|
||||||
test("@name method call", [[
|
test("@name method call", [[
|
||||||
local a = {
|
local a = {
|
||||||
foo = "Hoi",
|
foo = "Hoi",
|
||||||
bar = function(self)
|
bar = function(self)
|
||||||
return self.foo
|
return self.foo
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
function a:hey()
|
function a:hey()
|
||||||
return @bar()
|
return @bar()
|
||||||
end
|
end
|
||||||
return a:hey()
|
return a:hey()
|
||||||
]], "Hoi")
|
]], "Hoi")
|
||||||
test("@[expt] indexation", [[
|
test("@[expt] indexation", [[
|
||||||
local a = {
|
local a = {
|
||||||
foo = "Hoi"
|
foo = "Hoi"
|
||||||
}
|
}
|
||||||
function a:hey()
|
function a:hey()
|
||||||
return @["foo"]
|
return @["foo"]
|
||||||
end
|
end
|
||||||
return a:hey()
|
return a:hey()
|
||||||
]], "Hoi")
|
]], "Hoi")
|
||||||
|
|
||||||
-- Short anonymous functions declaration
|
-- Short anonymous functions declaration
|
||||||
test("short anonymous function declaration", [[
|
test("short anonymous function declaration", [[
|
||||||
local a = (arg1)
|
local a = (arg1)
|
||||||
return arg1
|
return arg1
|
||||||
end
|
end
|
||||||
return a(5)
|
return a(5)
|
||||||
]], 5)
|
]], 5)
|
||||||
test("short anonymous method declaration", [[
|
test("short anonymous method declaration", [[
|
||||||
local a = :(arg1)
|
local a = :(arg1)
|
||||||
return self + arg1
|
return self + arg1
|
||||||
end
|
end
|
||||||
return a(2, 3)
|
return a(2, 3)
|
||||||
]], 5)
|
]], 5)
|
||||||
test("short anonymous method parsing edge cases", [[
|
test("short anonymous method parsing edge cases", [[
|
||||||
-- Taken from the file I used when solving this horror, too tired to make separate tests.
|
-- Taken from the file I used when solving this horror, too tired to make separate tests.
|
||||||
x = ""
|
x = ""
|
||||||
function a(s)
|
function a(s)
|
||||||
x = x .. tostring(s or "+")
|
x = x .. tostring(s or "+")
|
||||||
end
|
end
|
||||||
k=true
|
k=true
|
||||||
while k do
|
while k do
|
||||||
k=false
|
k=false
|
||||||
cap = {[0] = op, a}
|
cap = {[0] = op, a}
|
||||||
a(tostring(h))
|
a(tostring(h))
|
||||||
|
|
@ -334,30 +338,30 @@ while k do
|
||||||
a()
|
a()
|
||||||
end
|
end
|
||||||
a()
|
a()
|
||||||
end
|
end
|
||||||
a()
|
a()
|
||||||
a("l")
|
a("l")
|
||||||
let h = (h)
|
let h = (h)
|
||||||
a("h")
|
a("h")
|
||||||
end
|
end
|
||||||
h()
|
h()
|
||||||
a("lol")
|
a("lol")
|
||||||
if false then exit() end
|
if false then exit() end
|
||||||
a("pmo")
|
a("pmo")
|
||||||
if true then
|
if true then
|
||||||
if false
|
if false
|
||||||
a = (h)
|
a = (h)
|
||||||
|
|
||||||
a()
|
a()
|
||||||
a("pom")
|
a("pom")
|
||||||
end
|
end
|
||||||
a("lo")
|
a("lo")
|
||||||
a("kol")
|
a("kol")
|
||||||
if false then
|
if false then
|
||||||
j()
|
j()
|
||||||
p()
|
p()
|
||||||
end
|
end
|
||||||
do
|
do
|
||||||
b = [
|
b = [
|
||||||
k = () end
|
k = () end
|
||||||
if false
|
if false
|
||||||
|
|
@ -367,45 +371,45 @@ do
|
||||||
|
|
||||||
k()
|
k()
|
||||||
a()]
|
a()]
|
||||||
end
|
end
|
||||||
if a() then h() end
|
if a() then h() end
|
||||||
local function f (...)
|
local function f (...)
|
||||||
if select('#', ...) == 1 then
|
if select('#', ...) == 1 then
|
||||||
return (...)
|
return (...)
|
||||||
else
|
else
|
||||||
return "***"
|
return "***"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return f(x)
|
return f(x)
|
||||||
]], "nil++++lhlolpmo+pomlokol++")
|
]], "nil++++lhlolpmo+pomlokol++")
|
||||||
|
|
||||||
-- let variable declaration
|
-- let variable declaration
|
||||||
test("let variable declaration", [[
|
test("let variable declaration", [[
|
||||||
let a = {
|
let a = {
|
||||||
foo = function()
|
foo = function()
|
||||||
return type(a)
|
return type(a)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
return a.foo()
|
return a.foo()
|
||||||
]], "table")
|
]], "table")
|
||||||
|
|
||||||
-- continue keyword
|
-- continue keyword
|
||||||
test("continue keyword in while", [[
|
test("continue keyword in while", [[
|
||||||
local a = ""
|
local a = ""
|
||||||
local i = 0
|
local i = 0
|
||||||
while i < 10 do
|
while i < 10 do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
a = a .. i
|
a = a .. i
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "13579")
|
]], "13579")
|
||||||
test("continue keyword in while, used with break", [[
|
test("continue keyword in while, used with break", [[
|
||||||
local a = ""
|
local a = ""
|
||||||
local i = 0
|
local i = 0
|
||||||
while i < 10 do
|
while i < 10 do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
|
|
@ -414,25 +418,25 @@ while i < 10 do
|
||||||
if i == 5 then
|
if i == 5 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "135")
|
]], "135")
|
||||||
test("continue keyword in repeat", [[
|
test("continue keyword in repeat", [[
|
||||||
local a = ""
|
local a = ""
|
||||||
local i = 0
|
local i = 0
|
||||||
repeat
|
repeat
|
||||||
i = i + 1
|
i = i + 1
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
a = a .. i
|
a = a .. i
|
||||||
until i == 10
|
until i == 10
|
||||||
return a
|
return a
|
||||||
]], "13579")
|
]], "13579")
|
||||||
test("continue keyword in repeat, used with break", [[
|
test("continue keyword in repeat, used with break", [[
|
||||||
local a = ""
|
local a = ""
|
||||||
local i = 0
|
local i = 0
|
||||||
repeat
|
repeat
|
||||||
i = i + 1
|
i = i + 1
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
|
|
@ -441,22 +445,22 @@ repeat
|
||||||
if i == 5 then
|
if i == 5 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
until i == 10
|
until i == 10
|
||||||
return a
|
return a
|
||||||
]], "135")
|
]], "135")
|
||||||
test("continue keyword in fornum", [[
|
test("continue keyword in fornum", [[
|
||||||
local a = ""
|
local a = ""
|
||||||
for i=1, 10 do
|
for i=1, 10 do
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
a = a .. i
|
a = a .. i
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "13579")
|
]], "13579")
|
||||||
test("continue keyword in fornum, used with break", [[
|
test("continue keyword in fornum, used with break", [[
|
||||||
local a = ""
|
local a = ""
|
||||||
for i=1, 10 do
|
for i=1, 10 do
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
|
@ -464,24 +468,24 @@ for i=1, 10 do
|
||||||
if i == 5 then
|
if i == 5 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "135")
|
]], "135")
|
||||||
test("continue keyword in for", [[
|
test("continue keyword in for", [[
|
||||||
local t = {1,2,3,4,5,6,7,8,9,10}
|
local t = {1,2,3,4,5,6,7,8,9,10}
|
||||||
local a = ""
|
local a = ""
|
||||||
for _, i in ipairs(t) do
|
for _, i in ipairs(t) do
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
a = a .. i
|
a = a .. i
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "13579")
|
]], "13579")
|
||||||
test("continue keyword in for, used with break", [[
|
test("continue keyword in for, used with break", [[
|
||||||
local t = {1,2,3,4,5,6,7,8,9,10}
|
local t = {1,2,3,4,5,6,7,8,9,10}
|
||||||
local a = ""
|
local a = ""
|
||||||
for _, i in ipairs(t) do
|
for _, i in ipairs(t) do
|
||||||
if i % 2 == 0 then
|
if i % 2 == 0 then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
|
@ -489,190 +493,190 @@ for _, i in ipairs(t) do
|
||||||
if i == 5 then
|
if i == 5 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "135")
|
]], "135")
|
||||||
|
|
||||||
-- push keyword
|
-- push keyword
|
||||||
test("push keyword", [[
|
test("push keyword", [[
|
||||||
function a()
|
function a()
|
||||||
for i=1, 5 do
|
for i=1, 5 do
|
||||||
push i, "next"
|
push i, "next"
|
||||||
end
|
end
|
||||||
return "done"
|
return "done"
|
||||||
end
|
end
|
||||||
return table.concat({a()})
|
return table.concat({a()})
|
||||||
]], "1next2next3next4next5nextdone")
|
]], "1next2next3next4next5nextdone")
|
||||||
test("push keyword variable length", [[
|
test("push keyword variable length", [[
|
||||||
function v()
|
function v()
|
||||||
return "hey", "hop"
|
return "hey", "hop"
|
||||||
end
|
end
|
||||||
function w()
|
function w()
|
||||||
return "foo", "bar"
|
return "foo", "bar"
|
||||||
end
|
end
|
||||||
function a()
|
function a()
|
||||||
push 5, v(), w()
|
push 5, v(), w()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
return table.concat({a()})
|
return table.concat({a()})
|
||||||
]], "5heyfoobar")
|
]], "5heyfoobar")
|
||||||
|
|
||||||
-- implicit push
|
-- implicit push
|
||||||
test("implicit push", [[
|
test("implicit push", [[
|
||||||
function a()
|
function a()
|
||||||
for i=1, 5 do
|
for i=1, 5 do
|
||||||
i, "next"
|
i, "next"
|
||||||
end
|
end
|
||||||
return "done"
|
return "done"
|
||||||
end
|
end
|
||||||
return table.concat({a()})
|
return table.concat({a()})
|
||||||
]], "1next2next3next4next5nextdone")
|
]], "1next2next3next4next5nextdone")
|
||||||
test("implicit push variable length", [[
|
test("implicit push variable length", [[
|
||||||
function v()
|
function v()
|
||||||
return "hey", "hop"
|
return "hey", "hop"
|
||||||
end
|
end
|
||||||
function w()
|
function w()
|
||||||
return "foo", "bar"
|
return "foo", "bar"
|
||||||
end
|
end
|
||||||
function a()
|
function a()
|
||||||
if true then
|
if true then
|
||||||
5, v(), w()
|
5, v(), w()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return table.concat({a()})
|
return table.concat({a()})
|
||||||
]], "5heyfoobar")
|
]], "5heyfoobar")
|
||||||
|
|
||||||
-- statement expressions
|
-- statement expressions
|
||||||
test("if statement expressions", [[
|
test("if statement expressions", [[
|
||||||
a = if false then
|
a = if false then
|
||||||
"foo" -- i.e. push "foo", i.e. return "foo"
|
"foo" -- i.e. push "foo", i.e. return "foo"
|
||||||
else
|
else
|
||||||
"bar"
|
"bar"
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "bar")
|
]], "bar")
|
||||||
test("do statement expressions", [[
|
test("do statement expressions", [[
|
||||||
a = do
|
a = do
|
||||||
"bar"
|
"bar"
|
||||||
end
|
end
|
||||||
return a
|
return a
|
||||||
]], "bar")
|
]], "bar")
|
||||||
test("while statement expressions", [[
|
test("while statement expressions", [[
|
||||||
i=0
|
i=0
|
||||||
a, b, c = while i<2 do i=i+1; i end
|
a, b, c = while i<2 do i=i+1; i end
|
||||||
return table.concat({a, b, tostring(c)})
|
return table.concat({a, b, tostring(c)})
|
||||||
]], "12nil")
|
]], "12nil")
|
||||||
test("repeat statement expressions", [[
|
test("repeat statement expressions", [[
|
||||||
local i = 0
|
local i = 0
|
||||||
a, b, c = repeat i=i+1; i until i==2
|
a, b, c = repeat i=i+1; i until i==2
|
||||||
return table.concat({a, b, tostring(c)})
|
return table.concat({a, b, tostring(c)})
|
||||||
]], "12nil")
|
]], "12nil")
|
||||||
test("for statement expressions", [[
|
test("for statement expressions", [[
|
||||||
a, b, c = for i=1,2 do i end
|
a, b, c = for i=1,2 do i end
|
||||||
return table.concat({a, b, tostring(c)})
|
return table.concat({a, b, tostring(c)})
|
||||||
]], "12nil")
|
]], "12nil")
|
||||||
|
|
||||||
-- table comprehension
|
-- table comprehension
|
||||||
test("table comprehension sequence", [[
|
test("table comprehension sequence", [[
|
||||||
return table.concat([for i=1,10 do i end])
|
return table.concat([for i=1,10 do i end])
|
||||||
]], "12345678910")
|
]], "12345678910")
|
||||||
test("table comprehension associative/self", [[
|
test("table comprehension associative/self", [[
|
||||||
a = [for i=1, 10 do @[i] = true end]
|
a = [for i=1, 10 do @[i] = true end]
|
||||||
return a[1] and a[10]
|
return a[1] and a[10]
|
||||||
]], true)
|
]], true)
|
||||||
test("table comprehension variable length", [[
|
test("table comprehension variable length", [[
|
||||||
t1 = {"hey", "hop"}
|
t1 = {"hey", "hop"}
|
||||||
t2 = {"foo", "bar"}
|
t2 = {"foo", "bar"}
|
||||||
return table.concat([push unpack(t1); push unpack(t2)])
|
return table.concat([push unpack(t1); push unpack(t2)])
|
||||||
]], "heyhopfoobar")
|
]], "heyhopfoobar")
|
||||||
|
|
||||||
-- one line statements
|
-- one line statements
|
||||||
test("one line if", [[
|
test("one line if", [[
|
||||||
a = 5
|
a = 5
|
||||||
if false
|
if false
|
||||||
a = 0
|
a = 0
|
||||||
return a
|
return a
|
||||||
]], 5)
|
]], 5)
|
||||||
test("one line if-elseif", [[
|
test("one line if-elseif", [[
|
||||||
a = 5
|
a = 5
|
||||||
if false
|
if false
|
||||||
a = 0
|
a = 0
|
||||||
elseif true
|
elseif true
|
||||||
a = 3
|
a = 3
|
||||||
elseif false
|
elseif false
|
||||||
a = -1
|
a = -1
|
||||||
return a
|
return a
|
||||||
]], 3)
|
]], 3)
|
||||||
test("one line for", [[
|
test("one line for", [[
|
||||||
a = 0
|
a = 0
|
||||||
for i=1,5
|
for i=1,5
|
||||||
a = a + 1
|
a = a + 1
|
||||||
return a
|
return a
|
||||||
]], 5)
|
]], 5)
|
||||||
test("one line while", [[
|
test("one line while", [[
|
||||||
a = 0
|
a = 0
|
||||||
while a < 5
|
while a < 5
|
||||||
a = a + 1
|
a = a + 1
|
||||||
return a
|
return a
|
||||||
]], 5)
|
]], 5)
|
||||||
|
|
||||||
-- suffixable string litals, table, table comprehension
|
-- suffixable string litals, table, table comprehension
|
||||||
test("suffixable string litteral method", [[
|
test("suffixable string litteral method", [[
|
||||||
return "foo":len()
|
return "foo":len()
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable string litteral method lua conflict", [[
|
test("suffixable string litteral method lua conflict", [[
|
||||||
local s = function() return "four" end
|
local s = function() return "four" end
|
||||||
return s"foo":len()
|
return s"foo":len()
|
||||||
]], 4)
|
]], 4)
|
||||||
test("suffixable string litteral dot index", [[
|
test("suffixable string litteral dot index", [[
|
||||||
local a = "foo".len
|
local a = "foo".len
|
||||||
return a("foo")
|
return a("foo")
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable string litteral dot index lua conflict", [[
|
test("suffixable string litteral dot index lua conflict", [[
|
||||||
local s = function() return {len=4} end
|
local s = function() return {len=4} end
|
||||||
local a = s"foo".len
|
local a = s"foo".len
|
||||||
return a
|
return a
|
||||||
]], 4)
|
]], 4)
|
||||||
test("suffixable string litteral array index", [[
|
test("suffixable string litteral array index", [[
|
||||||
local a = "foo"["len"]
|
local a = "foo"["len"]
|
||||||
return a("foo")
|
return a("foo")
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable string litteral dot index lua conflict", [[
|
test("suffixable string litteral dot index lua conflict", [[
|
||||||
local s = function() return {len=4} end
|
local s = function() return {len=4} end
|
||||||
local a = s"foo"["len"]
|
local a = s"foo"["len"]
|
||||||
return a
|
return a
|
||||||
]], 4)
|
]], 4)
|
||||||
|
|
||||||
test("suffixable table litteral method", [[
|
test("suffixable table litteral method", [[
|
||||||
return {a=3,len=function(t) return t.a end}:len()
|
return {a=3,len=function(t) return t.a end}:len()
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable table litteral method lua conflict", [[
|
test("suffixable table litteral method lua conflict", [[
|
||||||
local s = function() return "four" end
|
local s = function() return "four" end
|
||||||
return s{a=3,len=function(t) return t.a end}:len()
|
return s{a=3,len=function(t) return t.a end}:len()
|
||||||
]], 4)
|
]], 4)
|
||||||
test("suffixable table litteral dot index", [[
|
test("suffixable table litteral dot index", [[
|
||||||
return {len=3}.len
|
return {len=3}.len
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable table litteral dot index lua conflict", [[
|
test("suffixable table litteral dot index lua conflict", [[
|
||||||
local s = function() return {len=4} end
|
local s = function() return {len=4} end
|
||||||
return s{len=3}.len
|
return s{len=3}.len
|
||||||
]], 4)
|
]], 4)
|
||||||
test("suffixable table litteral array index", [[
|
test("suffixable table litteral array index", [[
|
||||||
return {len=3}["len"]
|
return {len=3}["len"]
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable table litteral dot index lua conflict", [[
|
test("suffixable table litteral dot index lua conflict", [[
|
||||||
local s = function() return {len=4} end
|
local s = function() return {len=4} end
|
||||||
return s{len=3}["len"]
|
return s{len=3}["len"]
|
||||||
]], 4)
|
]], 4)
|
||||||
|
|
||||||
test("suffixable table comprehension method", [[
|
test("suffixable table comprehension method", [[
|
||||||
return [@len = function() return 3 end]:len()
|
return [@len = function() return 3 end]:len()
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable table comprehension dot index", [[
|
test("suffixable table comprehension dot index", [[
|
||||||
return [@len = 3].len
|
return [@len = 3].len
|
||||||
]], 3)
|
]], 3)
|
||||||
test("suffixable table comprehension array index", [[
|
test("suffixable table comprehension array index", [[
|
||||||
return [@len=3]["len"]
|
return [@len=3]["len"]
|
||||||
]], 3)
|
]], 3)
|
||||||
|
|
||||||
-- let in condition expression
|
-- let in condition expression
|
||||||
|
|
@ -823,6 +827,187 @@ test("safe prefixes, random chaining", [[
|
||||||
assert(f.l?:o?() == nil)
|
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
|
-- results
|
||||||
local resultCounter = {}
|
local resultCounter = {}
|
||||||
local testCounter = 0
|
local testCounter = 0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue