mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
move class transformer to own module
This commit is contained in:
parent
5a0c5d1e55
commit
ca21c216ea
436
moonscript/transform/class.lua
Normal file
436
moonscript/transform/class.lua
Normal file
@ -0,0 +1,436 @@
|
||||
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
|
||||
return function(self, node, ret, parent_assign)
|
||||
local _, name, parent_val, body = unpack(node)
|
||||
if parent_val == "" then
|
||||
parent_val = nil
|
||||
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
|
||||
insert(statements, build.assign_one(unpack(tuple)))
|
||||
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
|
||||
_value_0 = tuple
|
||||
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
|
||||
local parent_cls_name = NameProxy("parent")
|
||||
local base_name = NameProxy("base")
|
||||
local self_name = NameProxy("self")
|
||||
local cls_name = NameProxy("class")
|
||||
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",
|
||||
constructor
|
||||
},
|
||||
{
|
||||
"__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
|
||||
self:put_name(name)
|
||||
end
|
||||
return self:set("super", function(block, chain)
|
||||
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_1 = head[1]
|
||||
if "call" == _exp_1 then
|
||||
local calling_name = block:get("current_block")
|
||||
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_1 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)
|
||||
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
|
256
moonscript/transform/class.moon
Normal file
256
moonscript/transform/class.moon
Normal file
@ -0,0 +1,256 @@
|
||||
import NameProxy, LocalName from require "moonscript.transform.names"
|
||||
import Run from require "moonscript.transform.statements"
|
||||
|
||||
CONSTRUCTOR_NAME = "new"
|
||||
|
||||
import insert from table
|
||||
import build, ntype, NOOP from require "moonscript.types"
|
||||
|
||||
(node, ret, parent_assign) =>
|
||||
_, name, parent_val, body = unpack node
|
||||
parent_val = nil if parent_val == ""
|
||||
|
||||
-- split apart properties and statements
|
||||
statements = {}
|
||||
properties = {}
|
||||
for item in *body
|
||||
switch item[1]
|
||||
when "stm"
|
||||
insert statements, item[2]
|
||||
when "props"
|
||||
for tuple in *item[2,]
|
||||
if ntype(tuple[1]) == "self"
|
||||
insert statements, build.assign_one unpack tuple
|
||||
else
|
||||
insert properties, tuple
|
||||
|
||||
-- find constructor
|
||||
local constructor
|
||||
properties = for tuple in *properties
|
||||
key = tuple[1]
|
||||
if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME
|
||||
constructor = tuple[2]
|
||||
continue
|
||||
else
|
||||
tuple
|
||||
|
||||
parent_cls_name = NameProxy "parent"
|
||||
base_name = NameProxy "base"
|
||||
self_name = NameProxy "self"
|
||||
cls_name = NameProxy "class"
|
||||
|
||||
unless constructor
|
||||
constructor = if parent_val
|
||||
build.fndef {
|
||||
args: {{"..."}}
|
||||
arrow: "fat"
|
||||
body: {
|
||||
build.chain { base: "super", {"call", {"..."}} }
|
||||
}
|
||||
}
|
||||
else
|
||||
build.fndef!
|
||||
|
||||
real_name = name or parent_assign and parent_assign[2][1]
|
||||
real_name = switch ntype real_name
|
||||
when "chain"
|
||||
last = real_name[#real_name]
|
||||
switch ntype last
|
||||
when "dot"
|
||||
{"string", '"', last[2]}
|
||||
when "index"
|
||||
last[2]
|
||||
else
|
||||
"nil"
|
||||
when "nil"
|
||||
"nil"
|
||||
else
|
||||
name_t = type real_name
|
||||
-- TODO: don't use string literal as ref
|
||||
flattened_name = if name_t == "string"
|
||||
real_name
|
||||
elseif name_t == "table" and real_name[1] == "ref"
|
||||
real_name[2]
|
||||
else
|
||||
error "don't know how to extract name from #{name_t}"
|
||||
|
||||
{"string", '"', flattened_name}
|
||||
|
||||
cls = build.table {
|
||||
{"__init", constructor}
|
||||
{"__base", base_name}
|
||||
{"__name", real_name} -- "quote the string"
|
||||
parent_val and {"__parent", parent_cls_name} or nil
|
||||
}
|
||||
|
||||
-- looking up a name in the class object
|
||||
class_index = if parent_val
|
||||
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"}}
|
||||
|
||||
build.fndef {
|
||||
args: {{"cls"}, {"name"}}
|
||||
body: {
|
||||
build.assign_one LocalName"val", build.chain {
|
||||
base: "rawget", {"call", {base_name, {"ref", "name"}}}
|
||||
}
|
||||
class_lookup
|
||||
}
|
||||
}
|
||||
else
|
||||
base_name
|
||||
|
||||
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}}
|
||||
}
|
||||
|
||||
value = nil
|
||||
with build
|
||||
out_body = {
|
||||
Run =>
|
||||
-- make sure we don't assign the class to a local inside the do
|
||||
@put_name name if name
|
||||
|
||||
@set "super", (block, chain) ->
|
||||
relative_parent = {
|
||||
"chain",
|
||||
cls_name
|
||||
{"dot", "__parent"}
|
||||
}
|
||||
|
||||
return relative_parent unless chain
|
||||
|
||||
chain_tail = { unpack chain, 3 }
|
||||
head = chain_tail[1]
|
||||
|
||||
if head == nil
|
||||
return relative_parent
|
||||
|
||||
new_chain = relative_parent
|
||||
|
||||
switch head[1]
|
||||
-- calling super, inject calling name and self into chain
|
||||
when "call"
|
||||
calling_name = block\get"current_block"
|
||||
assert calling_name, "missing calling name"
|
||||
chain_tail[1] = {"call", {"self", unpack head[2]}}
|
||||
|
||||
if ntype(calling_name) == "key_literal"
|
||||
insert new_chain, {"dot", calling_name[2]}
|
||||
else
|
||||
insert new_chain, {"index", calling_name}
|
||||
|
||||
-- colon call on super, replace class with self as first arg
|
||||
when "colon"
|
||||
call = chain_tail[2]
|
||||
-- calling chain tail
|
||||
if call and call[1] == "call"
|
||||
chain_tail[1] = {
|
||||
"dot"
|
||||
head[2]
|
||||
}
|
||||
|
||||
chain_tail[2] = {
|
||||
"call"
|
||||
{
|
||||
"self"
|
||||
unpack call[2]
|
||||
}
|
||||
}
|
||||
|
||||
insert new_chain, item for item in *chain_tail
|
||||
new_chain
|
||||
|
||||
{"declare", { cls_name }}
|
||||
{"declare_glob", "*"}
|
||||
|
||||
parent_val and .assign_one(parent_cls_name, parent_val) or NOOP
|
||||
|
||||
.assign_one base_name, {"table", properties}
|
||||
.assign_one base_name\chain"__index", base_name
|
||||
|
||||
parent_val and .chain({
|
||||
base: "setmetatable"
|
||||
{"call", {
|
||||
base_name,
|
||||
.chain { base: parent_cls_name, {"dot", "__base"}}
|
||||
}}
|
||||
}) or NOOP
|
||||
|
||||
.assign_one cls_name, cls
|
||||
.assign_one base_name\chain"__class", cls_name
|
||||
|
||||
.group if #statements > 0 then {
|
||||
.assign_one LocalName"self", cls_name
|
||||
.group statements
|
||||
}
|
||||
|
||||
-- run the inherited callback
|
||||
parent_val and .if({
|
||||
cond: {"exp", parent_cls_name\chain "__inherited" }
|
||||
then: {
|
||||
parent_cls_name\chain "__inherited", {"call", {
|
||||
parent_cls_name, cls_name
|
||||
}}
|
||||
}
|
||||
}) or NOOP
|
||||
|
||||
.group if name then {
|
||||
.assign_one name, cls_name
|
||||
}
|
||||
|
||||
if ret
|
||||
ret cls_name
|
||||
}
|
||||
|
||||
value = .group {
|
||||
.group if ntype(name) == "value" then {
|
||||
.declare names: {name}
|
||||
}
|
||||
|
||||
.do out_body
|
||||
}
|
||||
|
||||
value
|
@ -1,10 +1,7 @@
|
||||
local Transformer
|
||||
Transformer = require("moonscript.transform.transformer").Transformer
|
||||
local NameProxy, LocalName
|
||||
do
|
||||
local _obj_0 = require("moonscript.transform.names")
|
||||
NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName
|
||||
end
|
||||
local NameProxy
|
||||
NameProxy = require("moonscript.transform.names").NameProxy
|
||||
local Run, transform_last_stm, implicitly_return, last_stm
|
||||
do
|
||||
local _obj_0 = require("moonscript.transform.statements")
|
||||
@ -18,7 +15,6 @@ insert = table.insert
|
||||
local destructure = require("moonscript.transform.destructure")
|
||||
local construct_comprehension
|
||||
construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension
|
||||
local CONSTRUCTOR_NAME = "new"
|
||||
local with_continue_listener
|
||||
with_continue_listener = function(body)
|
||||
local continue_name = nil
|
||||
@ -739,425 +735,5 @@ return Transformer({
|
||||
if_stm
|
||||
})
|
||||
end,
|
||||
class = function(self, node, ret, parent_assign)
|
||||
local _, name, parent_val, body = unpack(node)
|
||||
if parent_val == "" then
|
||||
parent_val = nil
|
||||
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
|
||||
insert(statements, build.assign_one(unpack(tuple)))
|
||||
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
|
||||
_value_0 = tuple
|
||||
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
|
||||
local parent_cls_name = NameProxy("parent")
|
||||
local base_name = NameProxy("base")
|
||||
local self_name = NameProxy("self")
|
||||
local cls_name = NameProxy("class")
|
||||
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",
|
||||
constructor
|
||||
},
|
||||
{
|
||||
"__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
|
||||
self:put_name(name)
|
||||
end
|
||||
return self:set("super", function(block, chain)
|
||||
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_1 = head[1]
|
||||
if "call" == _exp_1 then
|
||||
local calling_name = block:get("current_block")
|
||||
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_1 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)
|
||||
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
|
||||
class = require("moonscript.transform.class")
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Transformer from require "moonscript.transform.transformer"
|
||||
|
||||
import NameProxy, LocalName from require "moonscript.transform.names"
|
||||
import NameProxy from require "moonscript.transform.names"
|
||||
|
||||
import Run, transform_last_stm, implicitly_return, last_stm
|
||||
from require "moonscript.transform.statements"
|
||||
@ -15,8 +15,6 @@ import insert from table
|
||||
destructure = require "moonscript.transform.destructure"
|
||||
import construct_comprehension from require "moonscript.transform.comprehension"
|
||||
|
||||
CONSTRUCTOR_NAME = "new"
|
||||
|
||||
with_continue_listener = (body) ->
|
||||
continue_name = nil
|
||||
|
||||
@ -470,252 +468,6 @@ Transformer {
|
||||
if_stm
|
||||
}
|
||||
|
||||
class: (node, ret, parent_assign) =>
|
||||
_, name, parent_val, body = unpack node
|
||||
parent_val = nil if parent_val == ""
|
||||
class: require "moonscript.transform.class"
|
||||
|
||||
-- split apart properties and statements
|
||||
statements = {}
|
||||
properties = {}
|
||||
for item in *body
|
||||
switch item[1]
|
||||
when "stm"
|
||||
insert statements, item[2]
|
||||
when "props"
|
||||
for tuple in *item[2,]
|
||||
if ntype(tuple[1]) == "self"
|
||||
insert statements, build.assign_one unpack tuple
|
||||
else
|
||||
insert properties, tuple
|
||||
|
||||
-- find constructor
|
||||
local constructor
|
||||
properties = for tuple in *properties
|
||||
key = tuple[1]
|
||||
if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME
|
||||
constructor = tuple[2]
|
||||
continue
|
||||
else
|
||||
tuple
|
||||
|
||||
parent_cls_name = NameProxy "parent"
|
||||
base_name = NameProxy "base"
|
||||
self_name = NameProxy "self"
|
||||
cls_name = NameProxy "class"
|
||||
|
||||
unless constructor
|
||||
constructor = if parent_val
|
||||
build.fndef {
|
||||
args: {{"..."}}
|
||||
arrow: "fat"
|
||||
body: {
|
||||
build.chain { base: "super", {"call", {"..."}} }
|
||||
}
|
||||
}
|
||||
else
|
||||
build.fndef!
|
||||
|
||||
real_name = name or parent_assign and parent_assign[2][1]
|
||||
real_name = switch ntype real_name
|
||||
when "chain"
|
||||
last = real_name[#real_name]
|
||||
switch ntype last
|
||||
when "dot"
|
||||
{"string", '"', last[2]}
|
||||
when "index"
|
||||
last[2]
|
||||
else
|
||||
"nil"
|
||||
when "nil"
|
||||
"nil"
|
||||
else
|
||||
name_t = type real_name
|
||||
-- TODO: don't use string literal as ref
|
||||
flattened_name = if name_t == "string"
|
||||
real_name
|
||||
elseif name_t == "table" and real_name[1] == "ref"
|
||||
real_name[2]
|
||||
else
|
||||
error "don't know how to extract name from #{name_t}"
|
||||
|
||||
{"string", '"', flattened_name}
|
||||
|
||||
cls = build.table {
|
||||
{"__init", constructor}
|
||||
{"__base", base_name}
|
||||
{"__name", real_name} -- "quote the string"
|
||||
parent_val and {"__parent", parent_cls_name} or nil
|
||||
}
|
||||
|
||||
-- looking up a name in the class object
|
||||
class_index = if parent_val
|
||||
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"}}
|
||||
|
||||
build.fndef {
|
||||
args: {{"cls"}, {"name"}}
|
||||
body: {
|
||||
build.assign_one LocalName"val", build.chain {
|
||||
base: "rawget", {"call", {base_name, {"ref", "name"}}}
|
||||
}
|
||||
class_lookup
|
||||
}
|
||||
}
|
||||
else
|
||||
base_name
|
||||
|
||||
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}}
|
||||
}
|
||||
|
||||
value = nil
|
||||
with build
|
||||
out_body = {
|
||||
Run =>
|
||||
-- make sure we don't assign the class to a local inside the do
|
||||
@put_name name if name
|
||||
|
||||
@set "super", (block, chain) ->
|
||||
relative_parent = {
|
||||
"chain",
|
||||
cls_name
|
||||
{"dot", "__parent"}
|
||||
}
|
||||
|
||||
return relative_parent unless chain
|
||||
|
||||
chain_tail = { unpack chain, 3 }
|
||||
head = chain_tail[1]
|
||||
|
||||
if head == nil
|
||||
return relative_parent
|
||||
|
||||
new_chain = relative_parent
|
||||
|
||||
switch head[1]
|
||||
-- calling super, inject calling name and self into chain
|
||||
when "call"
|
||||
calling_name = block\get"current_block"
|
||||
assert calling_name, "missing calling name"
|
||||
chain_tail[1] = {"call", {"self", unpack head[2]}}
|
||||
|
||||
if ntype(calling_name) == "key_literal"
|
||||
insert new_chain, {"dot", calling_name[2]}
|
||||
else
|
||||
insert new_chain, {"index", calling_name}
|
||||
|
||||
-- colon call on super, replace class with self as first arg
|
||||
when "colon"
|
||||
call = chain_tail[2]
|
||||
-- calling chain tail
|
||||
if call and call[1] == "call"
|
||||
chain_tail[1] = {
|
||||
"dot"
|
||||
head[2]
|
||||
}
|
||||
|
||||
chain_tail[2] = {
|
||||
"call"
|
||||
{
|
||||
"self"
|
||||
unpack call[2]
|
||||
}
|
||||
}
|
||||
|
||||
insert new_chain, item for item in *chain_tail
|
||||
new_chain
|
||||
|
||||
{"declare", { cls_name }}
|
||||
{"declare_glob", "*"}
|
||||
|
||||
parent_val and .assign_one(parent_cls_name, parent_val) or NOOP
|
||||
|
||||
.assign_one base_name, {"table", properties}
|
||||
.assign_one base_name\chain"__index", base_name
|
||||
|
||||
parent_val and .chain({
|
||||
base: "setmetatable"
|
||||
{"call", {
|
||||
base_name,
|
||||
.chain { base: parent_cls_name, {"dot", "__base"}}
|
||||
}}
|
||||
}) or NOOP
|
||||
|
||||
.assign_one cls_name, cls
|
||||
.assign_one base_name\chain"__class", cls_name
|
||||
|
||||
.group if #statements > 0 then {
|
||||
.assign_one LocalName"self", cls_name
|
||||
.group statements
|
||||
}
|
||||
|
||||
-- run the inherited callback
|
||||
parent_val and .if({
|
||||
cond: {"exp", parent_cls_name\chain "__inherited" }
|
||||
then: {
|
||||
parent_cls_name\chain "__inherited", {"call", {
|
||||
parent_cls_name, cls_name
|
||||
}}
|
||||
}
|
||||
}) or NOOP
|
||||
|
||||
.group if name then {
|
||||
.assign_one name, cls_name
|
||||
}
|
||||
|
||||
if ret
|
||||
ret cls_name
|
||||
}
|
||||
|
||||
value = .group {
|
||||
.group if ntype(name) == "value" then {
|
||||
.declare names: {name}
|
||||
}
|
||||
|
||||
.do out_body
|
||||
}
|
||||
|
||||
value
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user