mirror of
https://github.com/leafo/moonscript.git
synced 2025-01-09 00:04:22 +00:00
487 lines
10 KiB
Lua
487 lines
10 KiB
Lua
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
|