From ca21c216ea94a3795dbe47019617b9222b526218 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 00:10:36 -0800 Subject: [PATCH] move class transformer to own module --- moonscript/transform/class.lua | 436 ++++++++++++++++++++++++++++ moonscript/transform/class.moon | 256 ++++++++++++++++ moonscript/transform/statement.lua | 430 +-------------------------- moonscript/transform/statement.moon | 254 +--------------- 4 files changed, 698 insertions(+), 678 deletions(-) create mode 100644 moonscript/transform/class.lua create mode 100644 moonscript/transform/class.moon diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua new file mode 100644 index 0000000..a8ad78b --- /dev/null +++ b/moonscript/transform/class.lua @@ -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 diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon new file mode 100644 index 0000000..007bace --- /dev/null +++ b/moonscript/transform/class.moon @@ -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 diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 77d0d3e..f37a9d6 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -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") }) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 6f4e169..7933c5f 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -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 == "" - - -- 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 + class: require "moonscript.transform.class" + }