3c5b61429a
Current version is from
491f2352a2
6265 lines
165 KiB
Lua
6265 lines
165 KiB
Lua
package.preload['moonscript.transform.comprehension'] = function()
|
|
local is_value
|
|
is_value = require("moonscript.types").is_value
|
|
local construct_comprehension
|
|
construct_comprehension = function(inner, clauses)
|
|
local current_stms = inner
|
|
for i = #clauses, 1, -1 do
|
|
local clause = clauses[i]
|
|
local t = clause[1]
|
|
local _exp_0 = t
|
|
if "for" == _exp_0 then
|
|
local _, name, bounds
|
|
_, name, bounds = clause[1], clause[2], clause[3]
|
|
current_stms = {
|
|
"for",
|
|
name,
|
|
bounds,
|
|
current_stms
|
|
}
|
|
elseif "foreach" == _exp_0 then
|
|
local _, names, iter
|
|
_, names, iter = clause[1], clause[2], clause[3]
|
|
current_stms = {
|
|
"foreach",
|
|
names,
|
|
{
|
|
iter
|
|
},
|
|
current_stms
|
|
}
|
|
elseif "when" == _exp_0 then
|
|
local _, cond
|
|
_, cond = clause[1], clause[2]
|
|
current_stms = {
|
|
"if",
|
|
cond,
|
|
current_stms
|
|
}
|
|
else
|
|
current_stms = error("Unknown comprehension clause: " .. t)
|
|
end
|
|
current_stms = {
|
|
current_stms
|
|
}
|
|
end
|
|
return current_stms[1]
|
|
end
|
|
local comprehension_has_value
|
|
comprehension_has_value = function(comp)
|
|
return is_value(comp[2])
|
|
end
|
|
return {
|
|
construct_comprehension = construct_comprehension,
|
|
comprehension_has_value = comprehension_has_value
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.transform.value'] = function()
|
|
local Transformer
|
|
Transformer = require("moonscript.transform.transformer").Transformer
|
|
local build, ntype, smart_node
|
|
do
|
|
local _obj_0 = require("moonscript.types")
|
|
build, ntype, smart_node = _obj_0.build, _obj_0.ntype, _obj_0.smart_node
|
|
end
|
|
local NameProxy
|
|
NameProxy = require("moonscript.transform.names").NameProxy
|
|
local Accumulator, default_accumulator
|
|
do
|
|
local _obj_0 = require("moonscript.transform.accumulator")
|
|
Accumulator, default_accumulator = _obj_0.Accumulator, _obj_0.default_accumulator
|
|
end
|
|
local lua_keywords
|
|
lua_keywords = require("moonscript.data").lua_keywords
|
|
local Run, transform_last_stm, implicitly_return, chain_is_stub
|
|
do
|
|
local _obj_0 = require("moonscript.transform.statements")
|
|
Run, transform_last_stm, implicitly_return, chain_is_stub = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.chain_is_stub
|
|
end
|
|
local construct_comprehension
|
|
construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension
|
|
local insert
|
|
insert = table.insert
|
|
local unpack
|
|
unpack = require("moonscript.util").unpack
|
|
return Transformer({
|
|
["for"] = default_accumulator,
|
|
["while"] = default_accumulator,
|
|
foreach = default_accumulator,
|
|
["do"] = function(self, node)
|
|
return build.block_exp(node[2])
|
|
end,
|
|
decorated = function(self, node)
|
|
return self.transform.statement(node)
|
|
end,
|
|
class = function(self, node)
|
|
return build.block_exp({
|
|
node
|
|
})
|
|
end,
|
|
string = function(self, node)
|
|
local delim = node[2]
|
|
local convert_part
|
|
convert_part = function(part)
|
|
if type(part) == "string" or part == nil then
|
|
return {
|
|
"string",
|
|
delim,
|
|
part or ""
|
|
}
|
|
else
|
|
return build.chain({
|
|
base = "tostring",
|
|
{
|
|
"call",
|
|
{
|
|
part[2]
|
|
}
|
|
}
|
|
})
|
|
end
|
|
end
|
|
if #node <= 3 then
|
|
if type(node[3]) == "string" then
|
|
return node
|
|
else
|
|
return convert_part(node[3])
|
|
end
|
|
end
|
|
local e = {
|
|
"exp",
|
|
convert_part(node[3])
|
|
}
|
|
for i = 4, #node do
|
|
insert(e, "..")
|
|
insert(e, convert_part(node[i]))
|
|
end
|
|
return e
|
|
end,
|
|
comprehension = function(self, node)
|
|
local a = Accumulator()
|
|
node = self.transform.statement(node, function(exp)
|
|
return a:mutate_body({
|
|
exp
|
|
})
|
|
end)
|
|
return a:wrap(node)
|
|
end,
|
|
tblcomprehension = function(self, node)
|
|
local explist, clauses = unpack(node, 2)
|
|
local key_exp, value_exp = unpack(explist)
|
|
local accum = NameProxy("tbl")
|
|
local inner
|
|
if value_exp then
|
|
local dest = build.chain({
|
|
base = accum,
|
|
{
|
|
"index",
|
|
key_exp
|
|
}
|
|
})
|
|
inner = {
|
|
build.assign_one(dest, value_exp)
|
|
}
|
|
else
|
|
local key_name, val_name = NameProxy("key"), NameProxy("val")
|
|
local dest = build.chain({
|
|
base = accum,
|
|
{
|
|
"index",
|
|
key_name
|
|
}
|
|
})
|
|
inner = {
|
|
build.assign({
|
|
names = {
|
|
key_name,
|
|
val_name
|
|
},
|
|
values = {
|
|
key_exp
|
|
}
|
|
}),
|
|
build.assign_one(dest, val_name)
|
|
}
|
|
end
|
|
return build.block_exp({
|
|
build.assign_one(accum, build.table()),
|
|
construct_comprehension(inner, clauses),
|
|
accum
|
|
})
|
|
end,
|
|
fndef = function(self, node)
|
|
smart_node(node)
|
|
node.body = transform_last_stm(node.body, implicitly_return(self))
|
|
node.body = {
|
|
Run(function(self)
|
|
return self:listen("varargs", function() end)
|
|
end),
|
|
unpack(node.body)
|
|
}
|
|
return node
|
|
end,
|
|
["if"] = function(self, node)
|
|
return build.block_exp({
|
|
node
|
|
})
|
|
end,
|
|
unless = function(self, node)
|
|
return build.block_exp({
|
|
node
|
|
})
|
|
end,
|
|
with = function(self, node)
|
|
return build.block_exp({
|
|
node
|
|
})
|
|
end,
|
|
switch = function(self, node)
|
|
return build.block_exp({
|
|
node
|
|
})
|
|
end,
|
|
chain = function(self, node)
|
|
for i = 2, #node do
|
|
local part = node[i]
|
|
if ntype(part) == "dot" and lua_keywords[part[2]] then
|
|
node[i] = {
|
|
"index",
|
|
{
|
|
"string",
|
|
'"',
|
|
part[2]
|
|
}
|
|
}
|
|
end
|
|
end
|
|
if ntype(node[2]) == "string" then
|
|
node[2] = {
|
|
"parens",
|
|
node[2]
|
|
}
|
|
end
|
|
if chain_is_stub(node) then
|
|
local base_name = NameProxy("base")
|
|
local fn_name = NameProxy("fn")
|
|
local colon = table.remove(node)
|
|
local is_super = ntype(node[2]) == "ref" and node[2][2] == "super"
|
|
return build.block_exp({
|
|
build.assign({
|
|
names = {
|
|
base_name
|
|
},
|
|
values = {
|
|
node
|
|
}
|
|
}),
|
|
build.assign({
|
|
names = {
|
|
fn_name
|
|
},
|
|
values = {
|
|
build.chain({
|
|
base = base_name,
|
|
{
|
|
"dot",
|
|
colon[2]
|
|
}
|
|
})
|
|
}
|
|
}),
|
|
build.fndef({
|
|
args = {
|
|
{
|
|
"..."
|
|
}
|
|
},
|
|
body = {
|
|
build.chain({
|
|
base = fn_name,
|
|
{
|
|
"call",
|
|
{
|
|
is_super and "self" or base_name,
|
|
"..."
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
})
|
|
end
|
|
end,
|
|
block_exp = function(self, node)
|
|
local body = unpack(node, 2)
|
|
local fn = nil
|
|
local arg_list = { }
|
|
fn = smart_node(build.fndef({
|
|
body = {
|
|
Run(function(self)
|
|
return self:listen("varargs", function()
|
|
insert(arg_list, "...")
|
|
insert(fn.args, {
|
|
"..."
|
|
})
|
|
return self:unlisten("varargs")
|
|
end)
|
|
end),
|
|
unpack(body)
|
|
}
|
|
}))
|
|
return build.chain({
|
|
base = {
|
|
"parens",
|
|
fn
|
|
},
|
|
{
|
|
"call",
|
|
arg_list
|
|
}
|
|
})
|
|
end
|
|
})
|
|
|
|
end
|
|
package.preload['moonscript.transform.class'] = function()
|
|
local NameProxy, LocalName
|
|
do
|
|
local _obj_0 = require("moonscript.transform.names")
|
|
NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName
|
|
end
|
|
local Run
|
|
Run = require("moonscript.transform.statements").Run
|
|
local CONSTRUCTOR_NAME = "new"
|
|
local insert
|
|
insert = table.insert
|
|
local build, ntype, NOOP
|
|
do
|
|
local _obj_0 = require("moonscript.types")
|
|
build, ntype, NOOP = _obj_0.build, _obj_0.ntype, _obj_0.NOOP
|
|
end
|
|
local unpack
|
|
unpack = require("moonscript.util").unpack
|
|
local transform_super
|
|
transform_super = function(cls_name, on_base, block, chain)
|
|
if on_base == nil then
|
|
on_base = true
|
|
end
|
|
local relative_parent = {
|
|
"chain",
|
|
cls_name,
|
|
{
|
|
"dot",
|
|
"__parent"
|
|
}
|
|
}
|
|
if not (chain) then
|
|
return relative_parent
|
|
end
|
|
local chain_tail = {
|
|
unpack(chain, 3)
|
|
}
|
|
local head = chain_tail[1]
|
|
if head == nil then
|
|
return relative_parent
|
|
end
|
|
local new_chain = relative_parent
|
|
local _exp_0 = head[1]
|
|
if "call" == _exp_0 then
|
|
if on_base then
|
|
insert(new_chain, {
|
|
"dot",
|
|
"__base"
|
|
})
|
|
end
|
|
local calling_name = block:get("current_method")
|
|
assert(calling_name, "missing calling name")
|
|
chain_tail[1] = {
|
|
"call",
|
|
{
|
|
"self",
|
|
unpack(head[2])
|
|
}
|
|
}
|
|
if ntype(calling_name) == "key_literal" then
|
|
insert(new_chain, {
|
|
"dot",
|
|
calling_name[2]
|
|
})
|
|
else
|
|
insert(new_chain, {
|
|
"index",
|
|
calling_name
|
|
})
|
|
end
|
|
elseif "colon" == _exp_0 then
|
|
local call = chain_tail[2]
|
|
if call and call[1] == "call" then
|
|
chain_tail[1] = {
|
|
"dot",
|
|
head[2]
|
|
}
|
|
chain_tail[2] = {
|
|
"call",
|
|
{
|
|
"self",
|
|
unpack(call[2])
|
|
}
|
|
}
|
|
end
|
|
end
|
|
for _index_0 = 1, #chain_tail do
|
|
local item = chain_tail[_index_0]
|
|
insert(new_chain, item)
|
|
end
|
|
return new_chain
|
|
end
|
|
local super_scope
|
|
super_scope = function(value, t, key)
|
|
local prev_method
|
|
return {
|
|
"scoped",
|
|
Run(function(self)
|
|
prev_method = self:get("current_method")
|
|
self:set("current_method", key)
|
|
return self:set("super", t)
|
|
end),
|
|
value,
|
|
Run(function(self)
|
|
return self:set("current_method", prev_method)
|
|
end)
|
|
}
|
|
end
|
|
return function(self, node, ret, parent_assign)
|
|
local name, parent_val, body = unpack(node, 2)
|
|
if parent_val == "" then
|
|
parent_val = nil
|
|
end
|
|
local parent_cls_name = NameProxy("parent")
|
|
local base_name = NameProxy("base")
|
|
local self_name = NameProxy("self")
|
|
local cls_name = NameProxy("class")
|
|
local cls_instance_super
|
|
cls_instance_super = function(...)
|
|
return transform_super(cls_name, true, ...)
|
|
end
|
|
local cls_super
|
|
cls_super = function(...)
|
|
return transform_super(cls_name, false, ...)
|
|
end
|
|
local statements = { }
|
|
local properties = { }
|
|
for _index_0 = 1, #body do
|
|
local item = body[_index_0]
|
|
local _exp_0 = item[1]
|
|
if "stm" == _exp_0 then
|
|
insert(statements, item[2])
|
|
elseif "props" == _exp_0 then
|
|
for _index_1 = 2, #item do
|
|
local tuple = item[_index_1]
|
|
if ntype(tuple[1]) == "self" then
|
|
local k, v
|
|
k, v = tuple[1], tuple[2]
|
|
v = super_scope(v, cls_super, {
|
|
"key_literal",
|
|
k[2]
|
|
})
|
|
insert(statements, build.assign_one(k, v))
|
|
else
|
|
insert(properties, tuple)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
local constructor
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #properties do
|
|
local _continue_0 = false
|
|
repeat
|
|
local tuple = properties[_index_0]
|
|
local key = tuple[1]
|
|
local _value_0
|
|
if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME then
|
|
constructor = tuple[2]
|
|
_continue_0 = true
|
|
break
|
|
else
|
|
local val
|
|
key, val = tuple[1], tuple[2]
|
|
_value_0 = {
|
|
key,
|
|
super_scope(val, cls_instance_super, key)
|
|
}
|
|
end
|
|
_accum_0[_len_0] = _value_0
|
|
_len_0 = _len_0 + 1
|
|
_continue_0 = true
|
|
until true
|
|
if not _continue_0 then
|
|
break
|
|
end
|
|
end
|
|
properties = _accum_0
|
|
end
|
|
if not (constructor) then
|
|
if parent_val then
|
|
constructor = build.fndef({
|
|
args = {
|
|
{
|
|
"..."
|
|
}
|
|
},
|
|
arrow = "fat",
|
|
body = {
|
|
build.chain({
|
|
base = "super",
|
|
{
|
|
"call",
|
|
{
|
|
"..."
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
else
|
|
constructor = build.fndef()
|
|
end
|
|
end
|
|
local real_name = name or parent_assign and parent_assign[2][1]
|
|
local _exp_0 = ntype(real_name)
|
|
if "chain" == _exp_0 then
|
|
local last = real_name[#real_name]
|
|
local _exp_1 = ntype(last)
|
|
if "dot" == _exp_1 then
|
|
real_name = {
|
|
"string",
|
|
'"',
|
|
last[2]
|
|
}
|
|
elseif "index" == _exp_1 then
|
|
real_name = last[2]
|
|
else
|
|
real_name = "nil"
|
|
end
|
|
elseif "nil" == _exp_0 then
|
|
real_name = "nil"
|
|
else
|
|
local name_t = type(real_name)
|
|
local flattened_name
|
|
if name_t == "string" then
|
|
flattened_name = real_name
|
|
elseif name_t == "table" and real_name[1] == "ref" then
|
|
flattened_name = real_name[2]
|
|
else
|
|
flattened_name = error("don't know how to extract name from " .. tostring(name_t))
|
|
end
|
|
real_name = {
|
|
"string",
|
|
'"',
|
|
flattened_name
|
|
}
|
|
end
|
|
local cls = build.table({
|
|
{
|
|
"__init",
|
|
super_scope(constructor, cls_super, {
|
|
"key_literal",
|
|
"__init"
|
|
})
|
|
},
|
|
{
|
|
"__base",
|
|
base_name
|
|
},
|
|
{
|
|
"__name",
|
|
real_name
|
|
},
|
|
parent_val and {
|
|
"__parent",
|
|
parent_cls_name
|
|
} or nil
|
|
})
|
|
local class_index
|
|
if parent_val then
|
|
local class_lookup = build["if"]({
|
|
cond = {
|
|
"exp",
|
|
{
|
|
"ref",
|
|
"val"
|
|
},
|
|
"==",
|
|
"nil"
|
|
},
|
|
["then"] = {
|
|
build.assign_one(LocalName("parent"), build.chain({
|
|
base = "rawget",
|
|
{
|
|
"call",
|
|
{
|
|
{
|
|
"ref",
|
|
"cls"
|
|
},
|
|
{
|
|
"string",
|
|
'"',
|
|
"__parent"
|
|
}
|
|
}
|
|
}
|
|
})),
|
|
build["if"]({
|
|
cond = LocalName("parent"),
|
|
["then"] = {
|
|
build.chain({
|
|
base = LocalName("parent"),
|
|
{
|
|
"index",
|
|
"name"
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
})
|
|
insert(class_lookup, {
|
|
"else",
|
|
{
|
|
"val"
|
|
}
|
|
})
|
|
class_index = build.fndef({
|
|
args = {
|
|
{
|
|
"cls"
|
|
},
|
|
{
|
|
"name"
|
|
}
|
|
},
|
|
body = {
|
|
build.assign_one(LocalName("val"), build.chain({
|
|
base = "rawget",
|
|
{
|
|
"call",
|
|
{
|
|
base_name,
|
|
{
|
|
"ref",
|
|
"name"
|
|
}
|
|
}
|
|
}
|
|
})),
|
|
class_lookup
|
|
}
|
|
})
|
|
else
|
|
class_index = base_name
|
|
end
|
|
local cls_mt = build.table({
|
|
{
|
|
"__index",
|
|
class_index
|
|
},
|
|
{
|
|
"__call",
|
|
build.fndef({
|
|
args = {
|
|
{
|
|
"cls"
|
|
},
|
|
{
|
|
"..."
|
|
}
|
|
},
|
|
body = {
|
|
build.assign_one(self_name, build.chain({
|
|
base = "setmetatable",
|
|
{
|
|
"call",
|
|
{
|
|
"{}",
|
|
base_name
|
|
}
|
|
}
|
|
})),
|
|
build.chain({
|
|
base = "cls.__init",
|
|
{
|
|
"call",
|
|
{
|
|
self_name,
|
|
"..."
|
|
}
|
|
}
|
|
}),
|
|
self_name
|
|
}
|
|
})
|
|
}
|
|
})
|
|
cls = build.chain({
|
|
base = "setmetatable",
|
|
{
|
|
"call",
|
|
{
|
|
cls,
|
|
cls_mt
|
|
}
|
|
}
|
|
})
|
|
local value = nil
|
|
do
|
|
local out_body = {
|
|
Run(function(self)
|
|
if name then
|
|
return self:put_name(name)
|
|
end
|
|
end),
|
|
{
|
|
"declare",
|
|
{
|
|
cls_name
|
|
}
|
|
},
|
|
{
|
|
"declare_glob",
|
|
"*"
|
|
},
|
|
parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP,
|
|
build.assign_one(base_name, {
|
|
"table",
|
|
properties
|
|
}),
|
|
build.assign_one(base_name:chain("__index"), base_name),
|
|
parent_val and build.chain({
|
|
base = "setmetatable",
|
|
{
|
|
"call",
|
|
{
|
|
base_name,
|
|
build.chain({
|
|
base = parent_cls_name,
|
|
{
|
|
"dot",
|
|
"__base"
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}) or NOOP,
|
|
build.assign_one(cls_name, cls),
|
|
build.assign_one(base_name:chain("__class"), cls_name),
|
|
build.group((function()
|
|
if #statements > 0 then
|
|
return {
|
|
build.assign_one(LocalName("self"), cls_name),
|
|
build.group(statements)
|
|
}
|
|
end
|
|
end)()),
|
|
parent_val and build["if"]({
|
|
cond = {
|
|
"exp",
|
|
parent_cls_name:chain("__inherited")
|
|
},
|
|
["then"] = {
|
|
parent_cls_name:chain("__inherited", {
|
|
"call",
|
|
{
|
|
parent_cls_name,
|
|
cls_name
|
|
}
|
|
})
|
|
}
|
|
}) or NOOP,
|
|
build.group((function()
|
|
if name then
|
|
return {
|
|
build.assign_one(name, cls_name)
|
|
}
|
|
end
|
|
end)()),
|
|
(function()
|
|
if ret then
|
|
return ret(cls_name)
|
|
end
|
|
end)()
|
|
}
|
|
value = build.group({
|
|
build.group((function()
|
|
if ntype(name) == "value" then
|
|
return {
|
|
build.declare({
|
|
names = {
|
|
name
|
|
}
|
|
})
|
|
}
|
|
end
|
|
end)()),
|
|
build["do"](out_body)
|
|
})
|
|
end
|
|
return value
|
|
end
|
|
|
|
end
|
|
package.preload['moonscript.transform.statements'] = function()
|
|
local types = require("moonscript.types")
|
|
local ntype, mtype, is_value, NOOP
|
|
ntype, mtype, is_value, NOOP = types.ntype, types.mtype, types.is_value, types.NOOP
|
|
local comprehension_has_value
|
|
comprehension_has_value = require("moonscript.transform.comprehension").comprehension_has_value
|
|
local Run
|
|
do
|
|
local _class_0
|
|
local _base_0 = {
|
|
call = function(self, state)
|
|
return self.fn(state)
|
|
end
|
|
}
|
|
_base_0.__index = _base_0
|
|
_class_0 = setmetatable({
|
|
__init = function(self, fn)
|
|
self.fn = fn
|
|
self[1] = "run"
|
|
end,
|
|
__base = _base_0,
|
|
__name = "Run"
|
|
}, {
|
|
__index = _base_0,
|
|
__call = function(cls, ...)
|
|
local _self_0 = setmetatable({}, _base_0)
|
|
cls.__init(_self_0, ...)
|
|
return _self_0
|
|
end
|
|
})
|
|
_base_0.__class = _class_0
|
|
Run = _class_0
|
|
end
|
|
local last_stm
|
|
last_stm = function(stms)
|
|
local last_exp_id = 0
|
|
for i = #stms, 1, -1 do
|
|
local stm = stms[i]
|
|
if stm and mtype(stm) ~= Run then
|
|
if ntype(stm) == "group" then
|
|
return last_stm(stm[2])
|
|
end
|
|
last_exp_id = i
|
|
break
|
|
end
|
|
end
|
|
return stms[last_exp_id], last_exp_id, stms
|
|
end
|
|
local transform_last_stm
|
|
transform_last_stm = function(stms, fn)
|
|
local _, last_idx, _stms = last_stm(stms)
|
|
if _stms ~= stms then
|
|
error("cannot transform last node in group")
|
|
end
|
|
return (function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i, stm in ipairs(stms) do
|
|
if i == last_idx then
|
|
_accum_0[_len_0] = {
|
|
"transform",
|
|
stm,
|
|
fn
|
|
}
|
|
else
|
|
_accum_0[_len_0] = stm
|
|
end
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)()
|
|
end
|
|
local chain_is_stub
|
|
chain_is_stub = function(chain)
|
|
local stub = chain[#chain]
|
|
return stub and ntype(stub) == "colon"
|
|
end
|
|
local implicitly_return
|
|
implicitly_return = function(scope)
|
|
local is_top = true
|
|
local fn
|
|
fn = function(stm)
|
|
local t = ntype(stm)
|
|
if t == "decorated" then
|
|
stm = scope.transform.statement(stm)
|
|
t = ntype(stm)
|
|
end
|
|
if types.cascading[t] then
|
|
is_top = false
|
|
return scope.transform.statement(stm, fn)
|
|
elseif types.manual_return[t] or not is_value(stm) then
|
|
if is_top and t == "return" and stm[2] == "" then
|
|
return NOOP
|
|
else
|
|
return stm
|
|
end
|
|
else
|
|
if t == "comprehension" and not comprehension_has_value(stm) then
|
|
return stm
|
|
else
|
|
return {
|
|
"return",
|
|
stm
|
|
}
|
|
end
|
|
end
|
|
end
|
|
return fn
|
|
end
|
|
return {
|
|
Run = Run,
|
|
last_stm = last_stm,
|
|
transform_last_stm = transform_last_stm,
|
|
chain_is_stub = chain_is_stub,
|
|
implicitly_return = implicitly_return
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.transform.destructure'] = function()
|
|
local ntype, mtype, build
|
|
do
|
|
local _obj_0 = require("moonscript.types")
|
|
ntype, mtype, build = _obj_0.ntype, _obj_0.mtype, _obj_0.build
|
|
end
|
|
local NameProxy
|
|
NameProxy = require("moonscript.transform.names").NameProxy
|
|
local insert
|
|
insert = table.insert
|
|
local unpack
|
|
unpack = require("moonscript.util").unpack
|
|
local user_error
|
|
user_error = require("moonscript.errors").user_error
|
|
local join
|
|
join = function(...)
|
|
do
|
|
local out = { }
|
|
local i = 1
|
|
local _list_0 = {
|
|
...
|
|
}
|
|
for _index_0 = 1, #_list_0 do
|
|
local tbl = _list_0[_index_0]
|
|
for _index_1 = 1, #tbl do
|
|
local v = tbl[_index_1]
|
|
out[i] = v
|
|
i = i + 1
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
end
|
|
local has_destructure
|
|
has_destructure = function(names)
|
|
for _index_0 = 1, #names do
|
|
local n = names[_index_0]
|
|
if ntype(n) == "table" then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
local extract_assign_names
|
|
extract_assign_names = function(name, accum, prefix)
|
|
if accum == nil then
|
|
accum = { }
|
|
end
|
|
if prefix == nil then
|
|
prefix = { }
|
|
end
|
|
local i = 1
|
|
local _list_0 = name[2]
|
|
for _index_0 = 1, #_list_0 do
|
|
local tuple = _list_0[_index_0]
|
|
local value, suffix
|
|
if #tuple == 1 then
|
|
local s = {
|
|
"index",
|
|
{
|
|
"number",
|
|
i
|
|
}
|
|
}
|
|
i = i + 1
|
|
value, suffix = tuple[1], s
|
|
else
|
|
local key = tuple[1]
|
|
local s
|
|
if ntype(key) == "key_literal" then
|
|
local key_name = key[2]
|
|
if ntype(key_name) == "colon" then
|
|
s = key_name
|
|
else
|
|
s = {
|
|
"dot",
|
|
key_name
|
|
}
|
|
end
|
|
else
|
|
s = {
|
|
"index",
|
|
key
|
|
}
|
|
end
|
|
value, suffix = tuple[2], s
|
|
end
|
|
suffix = join(prefix, {
|
|
suffix
|
|
})
|
|
local _exp_0 = ntype(value)
|
|
if "value" == _exp_0 or "ref" == _exp_0 or "chain" == _exp_0 or "self" == _exp_0 then
|
|
insert(accum, {
|
|
value,
|
|
suffix
|
|
})
|
|
elseif "table" == _exp_0 then
|
|
extract_assign_names(value, accum, suffix)
|
|
else
|
|
user_error("Can't destructure value of type: " .. tostring(ntype(value)))
|
|
end
|
|
end
|
|
return accum
|
|
end
|
|
local build_assign
|
|
build_assign = function(scope, destruct_literal, receiver)
|
|
local extracted_names = extract_assign_names(destruct_literal)
|
|
local names = { }
|
|
local values = { }
|
|
local inner = {
|
|
"assign",
|
|
names,
|
|
values
|
|
}
|
|
local obj
|
|
if scope:is_local(receiver) or #extracted_names == 1 then
|
|
obj = receiver
|
|
else
|
|
do
|
|
obj = NameProxy("obj")
|
|
inner = build["do"]({
|
|
build.assign_one(obj, receiver),
|
|
{
|
|
"assign",
|
|
names,
|
|
values
|
|
}
|
|
})
|
|
obj = obj
|
|
end
|
|
end
|
|
for _index_0 = 1, #extracted_names do
|
|
local tuple = extracted_names[_index_0]
|
|
insert(names, tuple[1])
|
|
local chain
|
|
if obj then
|
|
chain = NameProxy.chain(obj, unpack(tuple[2]))
|
|
else
|
|
chain = "nil"
|
|
end
|
|
insert(values, chain)
|
|
end
|
|
return build.group({
|
|
{
|
|
"declare",
|
|
names
|
|
},
|
|
inner
|
|
})
|
|
end
|
|
local split_assign
|
|
split_assign = function(scope, assign)
|
|
local names, values = unpack(assign, 2)
|
|
local g = { }
|
|
local total_names = #names
|
|
local total_values = #values
|
|
local start = 1
|
|
for i, n in ipairs(names) do
|
|
if ntype(n) == "table" then
|
|
if i > start then
|
|
local stop = i - 1
|
|
insert(g, {
|
|
"assign",
|
|
(function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i = start, stop do
|
|
_accum_0[_len_0] = names[i]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)(),
|
|
(function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i = start, stop do
|
|
_accum_0[_len_0] = values[i]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)()
|
|
})
|
|
end
|
|
insert(g, build_assign(scope, n, values[i]))
|
|
start = i + 1
|
|
end
|
|
end
|
|
if total_names >= start or total_values >= start then
|
|
local name_slice
|
|
if total_names < start then
|
|
name_slice = {
|
|
"_"
|
|
}
|
|
else
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i = start, total_names do
|
|
_accum_0[_len_0] = names[i]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
name_slice = _accum_0
|
|
end
|
|
end
|
|
local value_slice
|
|
if total_values < start then
|
|
value_slice = {
|
|
"nil"
|
|
}
|
|
else
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i = start, total_values do
|
|
_accum_0[_len_0] = values[i]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
value_slice = _accum_0
|
|
end
|
|
end
|
|
insert(g, {
|
|
"assign",
|
|
name_slice,
|
|
value_slice
|
|
})
|
|
end
|
|
return build.group(g)
|
|
end
|
|
return {
|
|
has_destructure = has_destructure,
|
|
split_assign = split_assign,
|
|
build_assign = build_assign,
|
|
extract_assign_names = extract_assign_names
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.transform.names'] = function()
|
|
local build
|
|
build = require("moonscript.types").build
|
|
local unpack
|
|
unpack = require("moonscript.util").unpack
|
|
local LocalName
|
|
do
|
|
local _class_0
|
|
local _base_0 = {
|
|
get_name = function(self)
|
|
return self.name
|
|
end
|
|
}
|
|
_base_0.__index = _base_0
|
|
_class_0 = setmetatable({
|
|
__init = function(self, name)
|
|
self.name = name
|
|
self[1] = "temp_name"
|
|
end,
|
|
__base = _base_0,
|
|
__name = "LocalName"
|
|
}, {
|
|
__index = _base_0,
|
|
__call = function(cls, ...)
|
|
local _self_0 = setmetatable({}, _base_0)
|
|
cls.__init(_self_0, ...)
|
|
return _self_0
|
|
end
|
|
})
|
|
_base_0.__class = _class_0
|
|
LocalName = _class_0
|
|
end
|
|
local NameProxy
|
|
do
|
|
local _class_0
|
|
local _base_0 = {
|
|
get_name = function(self, scope, dont_put)
|
|
if dont_put == nil then
|
|
dont_put = true
|
|
end
|
|
if not self.name then
|
|
self.name = scope:free_name(self.prefix, dont_put)
|
|
end
|
|
return self.name
|
|
end,
|
|
chain = function(self, ...)
|
|
local items = {
|
|
base = self,
|
|
...
|
|
}
|
|
for k, v in ipairs(items) do
|
|
if type(v) == "string" then
|
|
items[k] = {
|
|
"dot",
|
|
v
|
|
}
|
|
else
|
|
items[k] = v
|
|
end
|
|
end
|
|
return build.chain(items)
|
|
end,
|
|
index = function(self, key)
|
|
if type(key) == "string" then
|
|
key = {
|
|
"ref",
|
|
key
|
|
}
|
|
end
|
|
return build.chain({
|
|
base = self,
|
|
{
|
|
"index",
|
|
key
|
|
}
|
|
})
|
|
end,
|
|
__tostring = function(self)
|
|
if self.name then
|
|
return ("name<%s>"):format(self.name)
|
|
else
|
|
return ("name<prefix(%s)>"):format(self.prefix)
|
|
end
|
|
end
|
|
}
|
|
_base_0.__index = _base_0
|
|
_class_0 = setmetatable({
|
|
__init = function(self, prefix)
|
|
self.prefix = prefix
|
|
self[1] = "temp_name"
|
|
end,
|
|
__base = _base_0,
|
|
__name = "NameProxy"
|
|
}, {
|
|
__index = _base_0,
|
|
__call = function(cls, ...)
|
|
local _self_0 = setmetatable({}, _base_0)
|
|
cls.__init(_self_0, ...)
|
|
return _self_0
|
|
end
|
|
})
|
|
_base_0.__class = _class_0
|
|
NameProxy = _class_0
|
|
end
|
|
local is_name_proxy
|
|
is_name_proxy = function(v)
|
|
if not (type(v) == "table") then
|
|
return false
|
|
end
|
|
local _exp_0 = v.__class
|
|
if LocalName == _exp_0 or NameProxy == _exp_0 then
|
|
return true
|
|
end
|
|
end
|
|
return {
|
|
NameProxy = NameProxy,
|
|
LocalName = LocalName,
|
|
is_name_proxy = is_name_proxy
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.transform.statement'] = function()
|
|
local Transformer
|
|
Transformer = require("moonscript.transform.transformer").Transformer
|
|
local NameProxy, LocalName, is_name_proxy
|
|
do
|
|
local _obj_0 = require("moonscript.transform.names")
|
|
NameProxy, LocalName, is_name_proxy = _obj_0.NameProxy, _obj_0.LocalName, _obj_0.is_name_proxy
|
|
end
|
|
local Run, transform_last_stm, implicitly_return, last_stm
|
|
do
|
|
local _obj_0 = require("moonscript.transform.statements")
|
|
Run, transform_last_stm, implicitly_return, last_stm = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.last_stm
|
|
end
|
|
local types = require("moonscript.types")
|
|
local build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP
|
|
build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP = types.build, types.ntype, types.is_value, types.smart_node, types.value_is_singular, types.is_slice, types.NOOP
|
|
local insert
|
|
insert = table.insert
|
|
local destructure = require("moonscript.transform.destructure")
|
|
local construct_comprehension
|
|
construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension
|
|
local unpack
|
|
unpack = require("moonscript.util").unpack
|
|
local with_continue_listener
|
|
with_continue_listener = function(body)
|
|
local continue_name = nil
|
|
return {
|
|
Run(function(self)
|
|
return self:listen("continue", function()
|
|
if not (continue_name) then
|
|
continue_name = NameProxy("continue")
|
|
self:put_name(continue_name)
|
|
end
|
|
return continue_name
|
|
end)
|
|
end),
|
|
build.group(body),
|
|
Run(function(self)
|
|
if not (continue_name) then
|
|
return
|
|
end
|
|
local last = last_stm(body)
|
|
local enclose_lines = types.terminating[last and ntype(last)]
|
|
self:put_name(continue_name, nil)
|
|
return self:splice(function(lines)
|
|
if enclose_lines then
|
|
lines = {
|
|
"do",
|
|
{
|
|
lines
|
|
}
|
|
}
|
|
end
|
|
return {
|
|
{
|
|
"assign",
|
|
{
|
|
continue_name
|
|
},
|
|
{
|
|
"false"
|
|
}
|
|
},
|
|
{
|
|
"repeat",
|
|
"true",
|
|
{
|
|
lines,
|
|
{
|
|
"assign",
|
|
{
|
|
continue_name
|
|
},
|
|
{
|
|
"true"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if",
|
|
{
|
|
"not",
|
|
continue_name
|
|
},
|
|
{
|
|
{
|
|
"break"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
end)
|
|
end)
|
|
}
|
|
end
|
|
local extract_declarations
|
|
extract_declarations = function(self, body, start, out)
|
|
if body == nil then
|
|
body = self.current_stms
|
|
end
|
|
if start == nil then
|
|
start = self.current_stm_i + 1
|
|
end
|
|
if out == nil then
|
|
out = { }
|
|
end
|
|
for i = start, #body do
|
|
local _continue_0 = false
|
|
repeat
|
|
local stm = body[i]
|
|
if stm == nil then
|
|
_continue_0 = true
|
|
break
|
|
end
|
|
stm = self.transform.statement(stm)
|
|
body[i] = stm
|
|
local _exp_0 = stm[1]
|
|
if "assign" == _exp_0 or "declare" == _exp_0 then
|
|
local _list_0 = stm[2]
|
|
for _index_0 = 1, #_list_0 do
|
|
local name = _list_0[_index_0]
|
|
if ntype(name) == "ref" then
|
|
insert(out, name)
|
|
elseif type(name) == "string" then
|
|
insert(out, name)
|
|
end
|
|
end
|
|
elseif "group" == _exp_0 then
|
|
extract_declarations(self, stm[2], 1, out)
|
|
end
|
|
_continue_0 = true
|
|
until true
|
|
if not _continue_0 then
|
|
break
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
local expand_elseif_assign
|
|
expand_elseif_assign = function(ifstm)
|
|
for i = 4, #ifstm do
|
|
local case = ifstm[i]
|
|
if ntype(case) == "elseif" and ntype(case[2]) == "assign" then
|
|
local split = {
|
|
unpack(ifstm, 1, i - 1)
|
|
}
|
|
insert(split, {
|
|
"else",
|
|
{
|
|
{
|
|
"if",
|
|
case[2],
|
|
case[3],
|
|
unpack(ifstm, i + 1)
|
|
}
|
|
}
|
|
})
|
|
return split
|
|
end
|
|
end
|
|
return ifstm
|
|
end
|
|
return Transformer({
|
|
transform = function(self, tuple)
|
|
local _, node, fn
|
|
_, node, fn = tuple[1], tuple[2], tuple[3]
|
|
return fn(node)
|
|
end,
|
|
root_stms = function(self, body)
|
|
return transform_last_stm(body, implicitly_return(self))
|
|
end,
|
|
["return"] = function(self, node)
|
|
local ret_val = node[2]
|
|
local ret_val_type = ntype(ret_val)
|
|
if ret_val_type == "explist" and #ret_val == 2 then
|
|
ret_val = ret_val[2]
|
|
ret_val_type = ntype(ret_val)
|
|
end
|
|
if types.cascading[ret_val_type] then
|
|
return implicitly_return(self)(ret_val)
|
|
end
|
|
if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" then
|
|
local Value = require("moonscript.transform.value")
|
|
ret_val = Value:transform_once(self, ret_val)
|
|
if ntype(ret_val) == "block_exp" then
|
|
return build.group(transform_last_stm(ret_val[2], function(stm)
|
|
return {
|
|
"return",
|
|
stm
|
|
}
|
|
end))
|
|
end
|
|
end
|
|
node[2] = ret_val
|
|
return node
|
|
end,
|
|
declare_glob = function(self, node)
|
|
local names = extract_declarations(self)
|
|
if node[2] == "^" then
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #names do
|
|
local _continue_0 = false
|
|
repeat
|
|
local name = names[_index_0]
|
|
local str_name
|
|
if ntype(name) == "ref" then
|
|
str_name = name[2]
|
|
else
|
|
str_name = name
|
|
end
|
|
if not (str_name:match("^%u")) then
|
|
_continue_0 = true
|
|
break
|
|
end
|
|
local _value_0 = name
|
|
_accum_0[_len_0] = _value_0
|
|
_len_0 = _len_0 + 1
|
|
_continue_0 = true
|
|
until true
|
|
if not _continue_0 then
|
|
break
|
|
end
|
|
end
|
|
names = _accum_0
|
|
end
|
|
end
|
|
return {
|
|
"declare",
|
|
names
|
|
}
|
|
end,
|
|
assign = function(self, node)
|
|
local names, values = unpack(node, 2)
|
|
local num_values = #values
|
|
local num_names = #values
|
|
if num_names == 1 and num_values == 1 then
|
|
local first_value = values[1]
|
|
local first_name = names[1]
|
|
local first_type = ntype(first_value)
|
|
if first_type == "chain" then
|
|
local Value = require("moonscript.transform.value")
|
|
first_value = Value:transform_once(self, first_value)
|
|
first_type = ntype(first_value)
|
|
end
|
|
local _exp_0 = ntype(first_value)
|
|
if "block_exp" == _exp_0 then
|
|
local block_body = first_value[2]
|
|
local idx = #block_body
|
|
block_body[idx] = build.assign_one(first_name, block_body[idx])
|
|
return build.group({
|
|
{
|
|
"declare",
|
|
{
|
|
first_name
|
|
}
|
|
},
|
|
{
|
|
"do",
|
|
block_body
|
|
}
|
|
})
|
|
elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 or "foreach" == _exp_0 or "for" == _exp_0 or "while" == _exp_0 then
|
|
local Value = require("moonscript.transform.value")
|
|
return build.assign_one(first_name, Value:transform_once(self, first_value))
|
|
else
|
|
values[1] = first_value
|
|
end
|
|
end
|
|
local transformed
|
|
if num_values == 1 then
|
|
local value = values[1]
|
|
local t = ntype(value)
|
|
if t == "decorated" then
|
|
value = self.transform.statement(value)
|
|
t = ntype(value)
|
|
end
|
|
if types.cascading[t] then
|
|
local ret
|
|
ret = function(stm)
|
|
if is_value(stm) then
|
|
return {
|
|
"assign",
|
|
names,
|
|
{
|
|
stm
|
|
}
|
|
}
|
|
else
|
|
return stm
|
|
end
|
|
end
|
|
transformed = build.group({
|
|
{
|
|
"declare",
|
|
names
|
|
},
|
|
self.transform.statement(value, ret, node)
|
|
})
|
|
end
|
|
end
|
|
node = transformed or node
|
|
if destructure.has_destructure(names) then
|
|
return destructure.split_assign(self, node)
|
|
end
|
|
return node
|
|
end,
|
|
continue = function(self, node)
|
|
local continue_name = self:send("continue")
|
|
if not (continue_name) then
|
|
error("continue must be inside of a loop")
|
|
end
|
|
return build.group({
|
|
build.assign_one(continue_name, "true"),
|
|
{
|
|
"break"
|
|
}
|
|
})
|
|
end,
|
|
export = function(self, node)
|
|
if #node > 2 then
|
|
if node[2] == "class" then
|
|
local cls = smart_node(node[3])
|
|
return build.group({
|
|
{
|
|
"export",
|
|
{
|
|
cls.name
|
|
}
|
|
},
|
|
cls
|
|
})
|
|
else
|
|
return build.group({
|
|
{
|
|
"export",
|
|
node[2]
|
|
},
|
|
build.assign({
|
|
names = node[2],
|
|
values = node[3]
|
|
})
|
|
})
|
|
end
|
|
else
|
|
return nil
|
|
end
|
|
end,
|
|
update = function(self, node)
|
|
local name, op, exp = unpack(node, 2)
|
|
local op_final = op:match("^(.+)=$")
|
|
if not op_final then
|
|
error("Unknown op: " .. op)
|
|
end
|
|
local lifted
|
|
if ntype(name) == "chain" then
|
|
lifted = { }
|
|
local new_chain
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 3, #name do
|
|
local part = name[_index_0]
|
|
if ntype(part) == "index" then
|
|
local proxy = NameProxy("update")
|
|
table.insert(lifted, {
|
|
proxy,
|
|
part[2]
|
|
})
|
|
_accum_0[_len_0] = {
|
|
"index",
|
|
proxy
|
|
}
|
|
else
|
|
_accum_0[_len_0] = part
|
|
end
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
new_chain = _accum_0
|
|
end
|
|
if next(lifted) then
|
|
name = {
|
|
name[1],
|
|
name[2],
|
|
unpack(new_chain)
|
|
}
|
|
end
|
|
end
|
|
if not (value_is_singular(exp)) then
|
|
exp = {
|
|
"parens",
|
|
exp
|
|
}
|
|
end
|
|
local out = build.assign_one(name, {
|
|
"exp",
|
|
name,
|
|
op_final,
|
|
exp
|
|
})
|
|
if lifted and next(lifted) then
|
|
local names
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #lifted do
|
|
local l = lifted[_index_0]
|
|
_accum_0[_len_0] = l[1]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
names = _accum_0
|
|
end
|
|
local values
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #lifted do
|
|
local l = lifted[_index_0]
|
|
_accum_0[_len_0] = l[2]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
values = _accum_0
|
|
end
|
|
out = build.group({
|
|
{
|
|
"assign",
|
|
names,
|
|
values
|
|
},
|
|
out
|
|
})
|
|
end
|
|
return out
|
|
end,
|
|
import = function(self, node)
|
|
local names, source = unpack(node, 2)
|
|
local table_values
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #names do
|
|
local name = names[_index_0]
|
|
local dest_name
|
|
if ntype(name) == "colon" then
|
|
dest_name = name[2]
|
|
else
|
|
dest_name = name
|
|
end
|
|
local _value_0 = {
|
|
{
|
|
"key_literal",
|
|
name
|
|
},
|
|
dest_name
|
|
}
|
|
_accum_0[_len_0] = _value_0
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
table_values = _accum_0
|
|
end
|
|
local dest = {
|
|
"table",
|
|
table_values
|
|
}
|
|
return {
|
|
"assign",
|
|
{
|
|
dest
|
|
},
|
|
{
|
|
source
|
|
},
|
|
[-1] = node[-1]
|
|
}
|
|
end,
|
|
comprehension = function(self, node, action)
|
|
local exp, clauses = unpack(node, 2)
|
|
action = action or function(exp)
|
|
return {
|
|
exp
|
|
}
|
|
end
|
|
return construct_comprehension(action(exp), clauses)
|
|
end,
|
|
["do"] = function(self, node, ret)
|
|
if ret then
|
|
node[2] = transform_last_stm(node[2], ret)
|
|
end
|
|
return node
|
|
end,
|
|
decorated = function(self, node)
|
|
local stm, dec = unpack(node, 2)
|
|
local wrapped
|
|
local _exp_0 = dec[1]
|
|
if "if" == _exp_0 then
|
|
local cond, fail = unpack(dec, 2)
|
|
if fail then
|
|
fail = {
|
|
"else",
|
|
{
|
|
fail
|
|
}
|
|
}
|
|
end
|
|
wrapped = {
|
|
"if",
|
|
cond,
|
|
{
|
|
stm
|
|
},
|
|
fail
|
|
}
|
|
elseif "unless" == _exp_0 then
|
|
wrapped = {
|
|
"unless",
|
|
dec[2],
|
|
{
|
|
stm
|
|
}
|
|
}
|
|
elseif "comprehension" == _exp_0 then
|
|
wrapped = {
|
|
"comprehension",
|
|
stm,
|
|
dec[2]
|
|
}
|
|
else
|
|
wrapped = error("Unknown decorator " .. dec[1])
|
|
end
|
|
if ntype(stm) == "assign" then
|
|
wrapped = build.group({
|
|
build.declare({
|
|
names = (function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
local _list_0 = stm[2]
|
|
for _index_0 = 1, #_list_0 do
|
|
local name = _list_0[_index_0]
|
|
if ntype(name) == "ref" then
|
|
_accum_0[_len_0] = name
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
end
|
|
return _accum_0
|
|
end)()
|
|
}),
|
|
wrapped
|
|
})
|
|
end
|
|
return wrapped
|
|
end,
|
|
unless = function(self, node)
|
|
local clause = node[2]
|
|
if ntype(clause) == "assign" then
|
|
if destructure.has_destructure(clause[2]) then
|
|
error("destructure not allowed in unless assignment")
|
|
end
|
|
return build["do"]({
|
|
clause,
|
|
{
|
|
"if",
|
|
{
|
|
"not",
|
|
clause[2][1]
|
|
},
|
|
unpack(node, 3)
|
|
}
|
|
})
|
|
else
|
|
return {
|
|
"if",
|
|
{
|
|
"not",
|
|
{
|
|
"parens",
|
|
clause
|
|
}
|
|
},
|
|
unpack(node, 3)
|
|
}
|
|
end
|
|
end,
|
|
["if"] = function(self, node, ret)
|
|
if ntype(node[2]) == "assign" then
|
|
local assign, body = unpack(node, 2)
|
|
if destructure.has_destructure(assign[2]) then
|
|
local name = NameProxy("des")
|
|
body = {
|
|
destructure.build_assign(self, assign[2][1], name),
|
|
build.group(node[3])
|
|
}
|
|
return build["do"]({
|
|
build.assign_one(name, assign[3][1]),
|
|
{
|
|
"if",
|
|
name,
|
|
body,
|
|
unpack(node, 4)
|
|
}
|
|
})
|
|
else
|
|
local name = assign[2][1]
|
|
return build["do"]({
|
|
assign,
|
|
{
|
|
"if",
|
|
name,
|
|
unpack(node, 3)
|
|
}
|
|
})
|
|
end
|
|
end
|
|
node = expand_elseif_assign(node)
|
|
if ret then
|
|
smart_node(node)
|
|
node['then'] = transform_last_stm(node['then'], ret)
|
|
for i = 4, #node do
|
|
local case = node[i]
|
|
local body_idx = #node[i]
|
|
case[body_idx] = transform_last_stm(case[body_idx], ret)
|
|
end
|
|
end
|
|
return node
|
|
end,
|
|
with = function(self, node, ret)
|
|
local exp, block = unpack(node, 2)
|
|
local copy_scope = true
|
|
local scope_name, named_assign
|
|
do
|
|
local last = last_stm(block)
|
|
if last then
|
|
if types.terminating[ntype(last)] then
|
|
ret = false
|
|
end
|
|
end
|
|
end
|
|
if ntype(exp) == "assign" then
|
|
local names, values = unpack(exp, 2)
|
|
local first_name = names[1]
|
|
if ntype(first_name) == "ref" then
|
|
scope_name = first_name
|
|
named_assign = exp
|
|
exp = values[1]
|
|
copy_scope = false
|
|
else
|
|
scope_name = NameProxy("with")
|
|
exp = values[1]
|
|
values[1] = scope_name
|
|
named_assign = {
|
|
"assign",
|
|
names,
|
|
values
|
|
}
|
|
end
|
|
elseif self:is_local(exp) then
|
|
scope_name = exp
|
|
copy_scope = false
|
|
end
|
|
scope_name = scope_name or NameProxy("with")
|
|
local out = build["do"]({
|
|
copy_scope and build.assign_one(scope_name, exp) or NOOP,
|
|
named_assign or NOOP,
|
|
Run(function(self)
|
|
return self:set("scope_var", scope_name)
|
|
end),
|
|
unpack(block)
|
|
})
|
|
if ret then
|
|
table.insert(out[2], ret(scope_name))
|
|
end
|
|
return out
|
|
end,
|
|
foreach = function(self, node, _)
|
|
smart_node(node)
|
|
local source = unpack(node.iter)
|
|
local destructures = { }
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i, name in ipairs(node.names) do
|
|
if ntype(name) == "table" then
|
|
do
|
|
local proxy = NameProxy("des")
|
|
insert(destructures, destructure.build_assign(self, name, proxy))
|
|
_accum_0[_len_0] = proxy
|
|
end
|
|
else
|
|
_accum_0[_len_0] = name
|
|
end
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
node.names = _accum_0
|
|
end
|
|
if next(destructures) then
|
|
insert(destructures, build.group(node.body))
|
|
node.body = destructures
|
|
end
|
|
if ntype(source) == "unpack" then
|
|
local list = source[2]
|
|
local index_name = NameProxy("index")
|
|
local list_name = self:is_local(list) and list or NameProxy("list")
|
|
local slice_var = nil
|
|
local bounds
|
|
if is_slice(list) then
|
|
local slice = list[#list]
|
|
table.remove(list)
|
|
table.remove(slice, 1)
|
|
if self:is_local(list) then
|
|
list_name = list
|
|
end
|
|
if slice[2] and slice[2] ~= "" then
|
|
local max_tmp_name = NameProxy("max")
|
|
slice_var = build.assign_one(max_tmp_name, slice[2])
|
|
slice[2] = {
|
|
"exp",
|
|
max_tmp_name,
|
|
"<",
|
|
0,
|
|
"and",
|
|
{
|
|
"length",
|
|
list_name
|
|
},
|
|
"+",
|
|
max_tmp_name,
|
|
"or",
|
|
max_tmp_name
|
|
}
|
|
else
|
|
slice[2] = {
|
|
"length",
|
|
list_name
|
|
}
|
|
end
|
|
bounds = slice
|
|
else
|
|
bounds = {
|
|
1,
|
|
{
|
|
"length",
|
|
list_name
|
|
}
|
|
}
|
|
end
|
|
local names
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
local _list_0 = node.names
|
|
for _index_0 = 1, #_list_0 do
|
|
local n = _list_0[_index_0]
|
|
_accum_0[_len_0] = is_name_proxy(n) and n or LocalName(n) or n
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
names = _accum_0
|
|
end
|
|
return build.group({
|
|
list_name ~= list and build.assign_one(list_name, list) or NOOP,
|
|
slice_var or NOOP,
|
|
build["for"]({
|
|
name = index_name,
|
|
bounds = bounds,
|
|
body = {
|
|
{
|
|
"assign",
|
|
names,
|
|
{
|
|
NameProxy.index(list_name, index_name)
|
|
}
|
|
},
|
|
build.group(node.body)
|
|
}
|
|
})
|
|
})
|
|
end
|
|
node.body = with_continue_listener(node.body)
|
|
end,
|
|
["while"] = function(self, node)
|
|
smart_node(node)
|
|
node.body = with_continue_listener(node.body)
|
|
end,
|
|
["for"] = function(self, node)
|
|
smart_node(node)
|
|
node.body = with_continue_listener(node.body)
|
|
end,
|
|
switch = function(self, node, ret)
|
|
local exp, conds = unpack(node, 2)
|
|
local exp_name = NameProxy("exp")
|
|
local convert_cond
|
|
convert_cond = function(cond)
|
|
local t, case_exps, body = unpack(cond)
|
|
local out = { }
|
|
insert(out, t == "case" and "elseif" or "else")
|
|
if t ~= "else" then
|
|
local cond_exp = { }
|
|
for i, case in ipairs(case_exps) do
|
|
if i == 1 then
|
|
insert(cond_exp, "exp")
|
|
else
|
|
insert(cond_exp, "or")
|
|
end
|
|
if not (value_is_singular(case)) then
|
|
case = {
|
|
"parens",
|
|
case
|
|
}
|
|
end
|
|
insert(cond_exp, {
|
|
"exp",
|
|
case,
|
|
"==",
|
|
exp_name
|
|
})
|
|
end
|
|
insert(out, cond_exp)
|
|
else
|
|
body = case_exps
|
|
end
|
|
if ret then
|
|
body = transform_last_stm(body, ret)
|
|
end
|
|
insert(out, body)
|
|
return out
|
|
end
|
|
local first = true
|
|
local if_stm = {
|
|
"if"
|
|
}
|
|
for _index_0 = 1, #conds do
|
|
local cond = conds[_index_0]
|
|
local if_cond = convert_cond(cond)
|
|
if first then
|
|
first = false
|
|
insert(if_stm, if_cond[2])
|
|
insert(if_stm, if_cond[3])
|
|
else
|
|
insert(if_stm, if_cond)
|
|
end
|
|
end
|
|
return build.group({
|
|
build.assign_one(exp_name, exp),
|
|
if_stm
|
|
})
|
|
end,
|
|
class = require("moonscript.transform.class")
|
|
})
|
|
|
|
end
|
|
package.preload['moonscript.transform.transformer'] = function()
|
|
local ntype
|
|
ntype = require("moonscript.types").ntype
|
|
local Transformer
|
|
do
|
|
local _class_0
|
|
local _base_0 = {
|
|
transform_once = function(self, scope, node, ...)
|
|
if self.seen_nodes[node] then
|
|
return node
|
|
end
|
|
self.seen_nodes[node] = true
|
|
local transformer = self.transformers[ntype(node)]
|
|
if transformer then
|
|
return transformer(scope, node, ...) or node
|
|
else
|
|
return node
|
|
end
|
|
end,
|
|
transform = function(self, scope, node, ...)
|
|
if self.seen_nodes[node] then
|
|
return node
|
|
end
|
|
self.seen_nodes[node] = true
|
|
while true do
|
|
local transformer = self.transformers[ntype(node)]
|
|
local res
|
|
if transformer then
|
|
res = transformer(scope, node, ...) or node
|
|
else
|
|
res = node
|
|
end
|
|
if res == node then
|
|
return node
|
|
end
|
|
node = res
|
|
end
|
|
return node
|
|
end,
|
|
bind = function(self, scope)
|
|
return function(...)
|
|
return self:transform(scope, ...)
|
|
end
|
|
end,
|
|
__call = function(self, ...)
|
|
return self:transform(...)
|
|
end,
|
|
can_transform = function(self, node)
|
|
return self.transformers[ntype(node)] ~= nil
|
|
end
|
|
}
|
|
_base_0.__index = _base_0
|
|
_class_0 = setmetatable({
|
|
__init = function(self, transformers)
|
|
self.transformers = transformers
|
|
self.seen_nodes = setmetatable({ }, {
|
|
__mode = "k"
|
|
})
|
|
end,
|
|
__base = _base_0,
|
|
__name = "Transformer"
|
|
}, {
|
|
__index = _base_0,
|
|
__call = function(cls, ...)
|
|
local _self_0 = setmetatable({}, _base_0)
|
|
cls.__init(_self_0, ...)
|
|
return _self_0
|
|
end
|
|
})
|
|
_base_0.__class = _class_0
|
|
Transformer = _class_0
|
|
end
|
|
return {
|
|
Transformer = Transformer
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.transform.accumulator'] = function()
|
|
local types = require("moonscript.types")
|
|
local build, ntype, NOOP
|
|
build, ntype, NOOP = types.build, types.ntype, types.NOOP
|
|
local NameProxy
|
|
NameProxy = require("moonscript.transform.names").NameProxy
|
|
local insert
|
|
insert = table.insert
|
|
local is_singular
|
|
is_singular = function(body)
|
|
if #body ~= 1 then
|
|
return false
|
|
end
|
|
if "group" == ntype(body) then
|
|
return is_singular(body[2])
|
|
else
|
|
return body[1]
|
|
end
|
|
end
|
|
local transform_last_stm
|
|
transform_last_stm = require("moonscript.transform.statements").transform_last_stm
|
|
local Accumulator
|
|
do
|
|
local _class_0
|
|
local _base_0 = {
|
|
body_idx = {
|
|
["for"] = 4,
|
|
["while"] = 3,
|
|
foreach = 4
|
|
},
|
|
convert = function(self, node)
|
|
local index = self.body_idx[ntype(node)]
|
|
node[index] = self:mutate_body(node[index])
|
|
return self:wrap(node)
|
|
end,
|
|
wrap = function(self, node, group_type)
|
|
if group_type == nil then
|
|
group_type = "block_exp"
|
|
end
|
|
return build[group_type]({
|
|
build.assign_one(self.accum_name, build.table()),
|
|
build.assign_one(self.len_name, 1),
|
|
node,
|
|
group_type == "block_exp" and self.accum_name or NOOP
|
|
})
|
|
end,
|
|
mutate_body = function(self, body)
|
|
local single_stm = is_singular(body)
|
|
local val
|
|
if single_stm and types.is_value(single_stm) then
|
|
body = { }
|
|
val = single_stm
|
|
else
|
|
body = transform_last_stm(body, function(n)
|
|
if types.is_value(n) then
|
|
return build.assign_one(self.value_name, n)
|
|
else
|
|
return build.group({
|
|
{
|
|
"declare",
|
|
{
|
|
self.value_name
|
|
}
|
|
},
|
|
n
|
|
})
|
|
end
|
|
end)
|
|
val = self.value_name
|
|
end
|
|
local update = {
|
|
build.assign_one(NameProxy.index(self.accum_name, self.len_name), val),
|
|
{
|
|
"update",
|
|
self.len_name,
|
|
"+=",
|
|
1
|
|
}
|
|
}
|
|
insert(body, build.group(update))
|
|
return body
|
|
end
|
|
}
|
|
_base_0.__index = _base_0
|
|
_class_0 = setmetatable({
|
|
__init = function(self, accum_name)
|
|
self.accum_name = NameProxy("accum")
|
|
self.value_name = NameProxy("value")
|
|
self.len_name = NameProxy("len")
|
|
end,
|
|
__base = _base_0,
|
|
__name = "Accumulator"
|
|
}, {
|
|
__index = _base_0,
|
|
__call = function(cls, ...)
|
|
local _self_0 = setmetatable({}, _base_0)
|
|
cls.__init(_self_0, ...)
|
|
return _self_0
|
|
end
|
|
})
|
|
_base_0.__class = _class_0
|
|
Accumulator = _class_0
|
|
end
|
|
local default_accumulator
|
|
default_accumulator = function(self, node)
|
|
return Accumulator():convert(node)
|
|
end
|
|
return {
|
|
Accumulator = Accumulator,
|
|
default_accumulator = default_accumulator
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.dump'] = function()
|
|
local flat_value
|
|
flat_value = function(op, depth)
|
|
if depth == nil then
|
|
depth = 1
|
|
end
|
|
if type(op) == "string" then
|
|
return '"' .. op .. '"'
|
|
end
|
|
if type(op) ~= "table" then
|
|
return tostring(op)
|
|
end
|
|
local items
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #op do
|
|
local item = op[_index_0]
|
|
_accum_0[_len_0] = flat_value(item, depth + 1)
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
items = _accum_0
|
|
end
|
|
local pos = op[-1]
|
|
return "{" .. (pos and "[" .. pos .. "] " or "") .. table.concat(items, ", ") .. "}"
|
|
end
|
|
local value
|
|
value = function(op)
|
|
return flat_value(op)
|
|
end
|
|
local tree
|
|
tree = function(block)
|
|
local _list_0 = block
|
|
for _index_0 = 1, #_list_0 do
|
|
local value = _list_0[_index_0]
|
|
print(flat_value(value))
|
|
end
|
|
end
|
|
return {
|
|
value = value,
|
|
tree = tree
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.util'] = function()
|
|
local concat
|
|
concat = table.concat
|
|
local unpack = unpack or table.unpack
|
|
local type = type
|
|
local moon = {
|
|
is_object = function(value)
|
|
return type(value) == "table" and value.__class
|
|
end,
|
|
is_a = function(thing, t)
|
|
if not (type(thing) == "table") then
|
|
return false
|
|
end
|
|
local cls = thing.__class
|
|
while cls do
|
|
if cls == t then
|
|
return true
|
|
end
|
|
cls = cls.__parent
|
|
end
|
|
return false
|
|
end,
|
|
type = function(value)
|
|
local base_type = type(value)
|
|
if base_type == "table" then
|
|
local cls = value.__class
|
|
if cls then
|
|
return cls
|
|
end
|
|
end
|
|
return base_type
|
|
end
|
|
}
|
|
local pos_to_line
|
|
pos_to_line = function(str, pos)
|
|
local line = 1
|
|
for _ in str:sub(1, pos):gmatch("\n") do
|
|
line = line + 1
|
|
end
|
|
return line
|
|
end
|
|
local trim
|
|
trim = function(str)
|
|
return str:match("^%s*(.-)%s*$")
|
|
end
|
|
local get_line
|
|
get_line = function(str, line_num)
|
|
for line in str:gmatch("([^\n]*)\n?") do
|
|
if line_num == 1 then
|
|
return line
|
|
end
|
|
line_num = line_num - 1
|
|
end
|
|
end
|
|
local get_closest_line
|
|
get_closest_line = function(str, line_num)
|
|
local line = get_line(str, line_num)
|
|
if (not line or trim(line) == "") and line_num > 1 then
|
|
return get_closest_line(str, line_num - 1)
|
|
else
|
|
return line, line_num
|
|
end
|
|
end
|
|
local split
|
|
split = function(str, delim)
|
|
if str == "" then
|
|
return { }
|
|
end
|
|
str = str .. delim
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for m in str:gmatch("(.-)" .. delim) do
|
|
_accum_0[_len_0] = m
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end
|
|
local dump
|
|
dump = function(what)
|
|
local seen = { }
|
|
local _dump
|
|
_dump = function(what, depth)
|
|
if depth == nil then
|
|
depth = 0
|
|
end
|
|
local t = type(what)
|
|
if t == "string" then
|
|
return '"' .. what .. '"\n'
|
|
elseif t == "table" then
|
|
if seen[what] then
|
|
return "recursion(" .. tostring(what) .. ")...\n"
|
|
end
|
|
seen[what] = true
|
|
depth = depth + 1
|
|
local lines
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for k, v in pairs(what) do
|
|
_accum_0[_len_0] = (" "):rep(depth * 4) .. "[" .. tostring(k) .. "] = " .. _dump(v, depth)
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
lines = _accum_0
|
|
end
|
|
seen[what] = false
|
|
return "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n"
|
|
else
|
|
return tostring(what) .. "\n"
|
|
end
|
|
end
|
|
return _dump(what)
|
|
end
|
|
local debug_posmap
|
|
debug_posmap = function(posmap, moon_code, lua_code)
|
|
local tuples
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for k, v in pairs(posmap) do
|
|
_accum_0[_len_0] = {
|
|
k,
|
|
v
|
|
}
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
tuples = _accum_0
|
|
end
|
|
table.sort(tuples, function(a, b)
|
|
return a[1] < b[1]
|
|
end)
|
|
local lines
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #tuples do
|
|
local pair = tuples[_index_0]
|
|
local lua_line, pos = unpack(pair)
|
|
local moon_line = pos_to_line(moon_code, pos)
|
|
local lua_text = get_line(lua_code, lua_line)
|
|
local moon_text = get_closest_line(moon_code, moon_line)
|
|
local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]"
|
|
_accum_0[_len_0] = _value_0
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
lines = _accum_0
|
|
end
|
|
return concat(lines, "\n")
|
|
end
|
|
local setfenv = setfenv or function(fn, env)
|
|
local name
|
|
local i = 1
|
|
while true do
|
|
name = debug.getupvalue(fn, i)
|
|
if not name or name == "_ENV" then
|
|
break
|
|
end
|
|
i = i + 1
|
|
end
|
|
if name then
|
|
debug.upvaluejoin(fn, i, (function()
|
|
return env
|
|
end), 1)
|
|
end
|
|
return fn
|
|
end
|
|
local getfenv = getfenv or function(fn)
|
|
local i = 1
|
|
while true do
|
|
local name, val = debug.getupvalue(fn, i)
|
|
if not (name) then
|
|
break
|
|
end
|
|
if name == "_ENV" then
|
|
return val
|
|
end
|
|
i = i + 1
|
|
end
|
|
return nil
|
|
end
|
|
local get_options
|
|
get_options = function(...)
|
|
local count = select("#", ...)
|
|
local opts = select(count, ...)
|
|
if type(opts) == "table" then
|
|
return opts, unpack({
|
|
...
|
|
}, nil, count - 1)
|
|
else
|
|
return { }, ...
|
|
end
|
|
end
|
|
local safe_module
|
|
safe_module = function(name, tbl)
|
|
return setmetatable(tbl, {
|
|
__index = function(self, key)
|
|
return error("Attempted to import non-existent `" .. tostring(key) .. "` from " .. tostring(name))
|
|
end
|
|
})
|
|
end
|
|
return {
|
|
moon = moon,
|
|
pos_to_line = pos_to_line,
|
|
get_closest_line = get_closest_line,
|
|
get_line = get_line,
|
|
trim = trim,
|
|
split = split,
|
|
dump = dump,
|
|
debug_posmap = debug_posmap,
|
|
getfenv = getfenv,
|
|
setfenv = setfenv,
|
|
get_options = get_options,
|
|
unpack = unpack,
|
|
safe_module = safe_module
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.cmd.lint'] = function()
|
|
local insert
|
|
insert = table.insert
|
|
local Set
|
|
Set = require("moonscript.data").Set
|
|
local Block
|
|
Block = require("moonscript.compile").Block
|
|
local mtype
|
|
mtype = require("moonscript.util").moon.type
|
|
local default_whitelist = Set({
|
|
'_G',
|
|
'_VERSION',
|
|
'assert',
|
|
'bit32',
|
|
'collectgarbage',
|
|
'coroutine',
|
|
'debug',
|
|
'dofile',
|
|
'error',
|
|
'getfenv',
|
|
'getmetatable',
|
|
'io',
|
|
'ipairs',
|
|
'load',
|
|
'loadfile',
|
|
'loadstring',
|
|
'math',
|
|
'module',
|
|
'next',
|
|
'os',
|
|
'package',
|
|
'pairs',
|
|
'pcall',
|
|
'print',
|
|
'rawequal',
|
|
'rawget',
|
|
'rawlen',
|
|
'rawset',
|
|
'require',
|
|
'select',
|
|
'setfenv',
|
|
'setmetatable',
|
|
'string',
|
|
'table',
|
|
'tonumber',
|
|
'tostring',
|
|
'type',
|
|
'unpack',
|
|
'xpcall',
|
|
"nil",
|
|
"true",
|
|
"false"
|
|
})
|
|
local LinterBlock
|
|
do
|
|
local _class_0
|
|
local _parent_0 = Block
|
|
local _base_0 = {
|
|
lint_mark_used = function(self, name)
|
|
if self.lint_unused_names and self.lint_unused_names[name] then
|
|
self.lint_unused_names[name] = false
|
|
return
|
|
end
|
|
if self.parent then
|
|
return self.parent:lint_mark_used(name)
|
|
end
|
|
end,
|
|
lint_check_unused = function(self)
|
|
if not (self.lint_unused_names and next(self.lint_unused_names)) then
|
|
return
|
|
end
|
|
local names_by_position = { }
|
|
for name, pos in pairs(self.lint_unused_names) do
|
|
local _continue_0 = false
|
|
repeat
|
|
if not (pos) then
|
|
_continue_0 = true
|
|
break
|
|
end
|
|
names_by_position[pos] = names_by_position[pos] or { }
|
|
insert(names_by_position[pos], name)
|
|
_continue_0 = true
|
|
until true
|
|
if not _continue_0 then
|
|
break
|
|
end
|
|
end
|
|
local tuples
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for pos, names in pairs(names_by_position) do
|
|
_accum_0[_len_0] = {
|
|
pos,
|
|
names
|
|
}
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
tuples = _accum_0
|
|
end
|
|
table.sort(tuples, function(a, b)
|
|
return a[1] < b[1]
|
|
end)
|
|
for _index_0 = 1, #tuples do
|
|
local _des_0 = tuples[_index_0]
|
|
local pos, names
|
|
pos, names = _des_0[1], _des_0[2]
|
|
insert(self:get_root_block().lint_errors, {
|
|
"assigned but unused " .. tostring(table.concat((function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_1 = 1, #names do
|
|
local n = names[_index_1]
|
|
_accum_0[_len_0] = "`" .. tostring(n) .. "`"
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)(), ", ")),
|
|
pos
|
|
})
|
|
end
|
|
end,
|
|
render = function(self, ...)
|
|
self:lint_check_unused()
|
|
return _class_0.__parent.__base.render(self, ...)
|
|
end,
|
|
block = function(self, ...)
|
|
do
|
|
local _with_0 = _class_0.__parent.__base.block(self, ...)
|
|
_with_0.block = self.block
|
|
_with_0.render = self.render
|
|
_with_0.get_root_block = self.get_root_block
|
|
_with_0.lint_check_unused = self.lint_check_unused
|
|
_with_0.lint_mark_used = self.lint_mark_used
|
|
_with_0.value_compilers = self.value_compilers
|
|
_with_0.statement_compilers = self.statement_compilers
|
|
return _with_0
|
|
end
|
|
end
|
|
}
|
|
_base_0.__index = _base_0
|
|
setmetatable(_base_0, _parent_0.__base)
|
|
_class_0 = setmetatable({
|
|
__init = function(self, whitelist_globals, ...)
|
|
if whitelist_globals == nil then
|
|
whitelist_globals = default_whitelist
|
|
end
|
|
_class_0.__parent.__init(self, ...)
|
|
self.get_root_block = function()
|
|
return self
|
|
end
|
|
self.lint_errors = { }
|
|
local vc = self.value_compilers
|
|
self.value_compilers = setmetatable({
|
|
ref = function(block, val)
|
|
local name = val[2]
|
|
if not (block:has_name(name) or whitelist_globals[name] or name:match("%.")) then
|
|
insert(self.lint_errors, {
|
|
"accessing global `" .. tostring(name) .. "`",
|
|
val[-1]
|
|
})
|
|
end
|
|
block:lint_mark_used(name)
|
|
return vc.ref(block, val)
|
|
end
|
|
}, {
|
|
__index = vc
|
|
})
|
|
local sc = self.statement_compilers
|
|
self.statement_compilers = setmetatable({
|
|
assign = function(block, node)
|
|
local names = node[2]
|
|
for _index_0 = 1, #names do
|
|
local _continue_0 = false
|
|
repeat
|
|
local name = names[_index_0]
|
|
if type(name) == "table" and name[1] == "temp_name" then
|
|
_continue_0 = true
|
|
break
|
|
end
|
|
local real_name, is_local = block:extract_assign_name(name)
|
|
if not (is_local or real_name and not block:has_name(real_name, true)) then
|
|
_continue_0 = true
|
|
break
|
|
end
|
|
if real_name == "_" then
|
|
_continue_0 = true
|
|
break
|
|
end
|
|
block.lint_unused_names = block.lint_unused_names or { }
|
|
block.lint_unused_names[real_name] = node[-1] or 0
|
|
_continue_0 = true
|
|
until true
|
|
if not _continue_0 then
|
|
break
|
|
end
|
|
end
|
|
return sc.assign(block, node)
|
|
end
|
|
}, {
|
|
__index = sc
|
|
})
|
|
end,
|
|
__base = _base_0,
|
|
__name = "LinterBlock",
|
|
__parent = _parent_0
|
|
}, {
|
|
__index = function(cls, name)
|
|
local val = rawget(_base_0, name)
|
|
if val == nil then
|
|
local parent = rawget(cls, "__parent")
|
|
if parent then
|
|
return parent[name]
|
|
end
|
|
else
|
|
return val
|
|
end
|
|
end,
|
|
__call = function(cls, ...)
|
|
local _self_0 = setmetatable({}, _base_0)
|
|
cls.__init(_self_0, ...)
|
|
return _self_0
|
|
end
|
|
})
|
|
_base_0.__class = _class_0
|
|
if _parent_0.__inherited then
|
|
_parent_0.__inherited(_parent_0, _class_0)
|
|
end
|
|
LinterBlock = _class_0
|
|
end
|
|
local format_lint
|
|
format_lint = function(errors, code, header)
|
|
if not (next(errors)) then
|
|
return
|
|
end
|
|
local pos_to_line, get_line
|
|
do
|
|
local _obj_0 = require("moonscript.util")
|
|
pos_to_line, get_line = _obj_0.pos_to_line, _obj_0.get_line
|
|
end
|
|
local formatted
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for _index_0 = 1, #errors do
|
|
local _des_0 = errors[_index_0]
|
|
local msg, pos
|
|
msg, pos = _des_0[1], _des_0[2]
|
|
if pos then
|
|
local line = pos_to_line(code, pos)
|
|
msg = "line " .. tostring(line) .. ": " .. tostring(msg)
|
|
local line_text = "> " .. get_line(code, line)
|
|
local sep_len = math.max(#msg, #line_text)
|
|
_accum_0[_len_0] = table.concat({
|
|
msg,
|
|
("="):rep(sep_len),
|
|
line_text
|
|
}, "\n")
|
|
else
|
|
_accum_0[_len_0] = msg
|
|
end
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
formatted = _accum_0
|
|
end
|
|
if header then
|
|
table.insert(formatted, 1, header)
|
|
end
|
|
return table.concat(formatted, "\n\n")
|
|
end
|
|
local whitelist_for_file
|
|
do
|
|
local lint_config
|
|
whitelist_for_file = function(fname)
|
|
if not (lint_config) then
|
|
lint_config = { }
|
|
pcall(function()
|
|
lint_config = require("lint_config")
|
|
end)
|
|
end
|
|
if not (lint_config.whitelist_globals) then
|
|
return default_whitelist
|
|
end
|
|
local final_list = { }
|
|
for pattern, list in pairs(lint_config.whitelist_globals) do
|
|
if fname:match(pattern) then
|
|
for _index_0 = 1, #list do
|
|
local item = list[_index_0]
|
|
insert(final_list, item)
|
|
end
|
|
end
|
|
end
|
|
return setmetatable(Set(final_list), {
|
|
__index = default_whitelist
|
|
})
|
|
end
|
|
end
|
|
local lint_code
|
|
lint_code = function(code, name, whitelist_globals)
|
|
if name == nil then
|
|
name = "string input"
|
|
end
|
|
local parse = require("moonscript.parse")
|
|
local tree, err = parse.string(code)
|
|
if not (tree) then
|
|
return nil, err
|
|
end
|
|
local scope = LinterBlock(whitelist_globals)
|
|
scope:stms(tree)
|
|
scope:lint_check_unused()
|
|
return format_lint(scope.lint_errors, code, name)
|
|
end
|
|
local lint_file
|
|
lint_file = function(fname)
|
|
local f, err = io.open(fname)
|
|
if not (f) then
|
|
return nil, err
|
|
end
|
|
return lint_code(f:read("*a"), fname, whitelist_for_file(fname))
|
|
end
|
|
return {
|
|
lint_code = lint_code,
|
|
lint_file = lint_file
|
|
}
|
|
|
|
end
|
|
package.preload['moonscript.cmd.args'] = function()
|
|
local unpack
|
|
unpack = require("moonscript.util").unpack
|
|
local |