move class transformer to own module

This commit is contained in:
leaf corcoran 2015-12-06 00:10:36 -08:00
parent 5a0c5d1e55
commit ca21c216ea
4 changed files with 698 additions and 678 deletions

View 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

View 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

View File

@ -1,10 +1,7 @@
local Transformer local Transformer
Transformer = require("moonscript.transform.transformer").Transformer Transformer = require("moonscript.transform.transformer").Transformer
local NameProxy, LocalName local NameProxy
do NameProxy = require("moonscript.transform.names").NameProxy
local _obj_0 = require("moonscript.transform.names")
NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName
end
local Run, transform_last_stm, implicitly_return, last_stm local Run, transform_last_stm, implicitly_return, last_stm
do do
local _obj_0 = require("moonscript.transform.statements") local _obj_0 = require("moonscript.transform.statements")
@ -18,7 +15,6 @@ insert = table.insert
local destructure = require("moonscript.transform.destructure") local destructure = require("moonscript.transform.destructure")
local construct_comprehension local construct_comprehension
construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension
local CONSTRUCTOR_NAME = "new"
local with_continue_listener local with_continue_listener
with_continue_listener = function(body) with_continue_listener = function(body)
local continue_name = nil local continue_name = nil
@ -739,425 +735,5 @@ return Transformer({
if_stm if_stm
}) })
end, end,
class = function(self, node, ret, parent_assign) class = require("moonscript.transform.class")
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
}) })

View File

@ -1,6 +1,6 @@
import Transformer from require "moonscript.transform.transformer" 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 import Run, transform_last_stm, implicitly_return, last_stm
from require "moonscript.transform.statements" from require "moonscript.transform.statements"
@ -15,8 +15,6 @@ import insert from table
destructure = require "moonscript.transform.destructure" destructure = require "moonscript.transform.destructure"
import construct_comprehension from require "moonscript.transform.comprehension" import construct_comprehension from require "moonscript.transform.comprehension"
CONSTRUCTOR_NAME = "new"
with_continue_listener = (body) -> with_continue_listener = (body) ->
continue_name = nil continue_name = nil
@ -470,252 +468,6 @@ Transformer {
if_stm if_stm
} }
class: (node, ret, parent_assign) => class: require "moonscript.transform.class"
_, 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
} }