moved class from compiler to tree transformation

This commit is contained in:
leaf corcoran 2011-10-01 22:20:29 -07:00
parent c15089ee1c
commit 3fb8682f96
10 changed files with 532 additions and 369 deletions

View File

@ -358,6 +358,7 @@ Block_ = (function(_parent_0)
end
end,
stm = function(self, node, ...)
node = transform.node(node)
local fn = line_compile[ntype(node)]
if not fn then
if has_value(node) then

View File

@ -238,6 +238,7 @@ class Block_
\append_list [@value v for v in *values], delim
stm: (node, ...) =>
node = transform.node node
fn = line_compile[ntype(node)]
if not fn
-- coerce value into statement

View File

@ -70,8 +70,12 @@ line_compile = {
end
do
local _with_0 = self:line()
local skip_values = false
if #undeclared == #names and not has_fndef then
_with_0:append(declare)
if #values == 0 then
skip_values = true
end
else
if #undeclared > 0 then
self:add(declare)
@ -90,20 +94,22 @@ line_compile = {
return _accum_0
end)(), ", ")
end
_with_0:append(" = ")
_with_0:append_list((function()
local _accum_0 = { }
local _len_0 = 0
do
local _item_0 = values
for _index_0 = 1, #_item_0 do
local v = _item_0[_index_0]
_len_0 = _len_0 + 1
_accum_0[_len_0] = self:value(v)
if not skip_values then
_with_0:append(" = ")
_with_0:append_list((function()
local _accum_0 = { }
local _len_0 = 0
do
local _item_0 = values
for _index_0 = 1, #_item_0 do
local v = _item_0[_index_0]
_len_0 = _len_0 + 1
_accum_0[_len_0] = self:value(v)
end
end
end
return _accum_0
end)(), ", ")
return _accum_0
end)(), ", ")
end
return _with_0
end
end
@ -412,242 +418,6 @@ line_compile = {
self:declare(names)
return nil
end,
class = function(self, node)
local _, name, parent_val, tbl = unpack(node)
local constructor = nil
local final_properties = { }
do
local _item_0 = tbl[2]
for _index_0 = 1, #_item_0 do
local entry = _item_0[_index_0]
if entry[1] == constructor_name then
constructor = entry[2]
else
insert(final_properties, entry)
end
end
end
tbl[2] = final_properties
local parent_loc = self:free_name("parent", true)
if not constructor then
constructor = {
"fndef",
{
{
"..."
}
},
{ },
"fat",
{
{
"if",
parent_loc,
{
{
"chain",
"super",
{
"call",
{
"..."
}
}
}
}
}
}
}
end
smart_node(constructor)
constructor.arrow = "fat"
local def_scope
do
local _with_0 = self:block()
if parent_val ~= "" then
parent_val = self:value(parent_val)
end
_with_0:put_name(parent_loc)
_with_0.header = self:line("(function(", parent_loc, ")")
_with_0.footer = self:line("end)(", parent_val, ")")
_with_0:set("super", function(block, chain)
local calling_name = block:get("current_block")
local slice = (function()
local _accum_0 = { }
local _len_0 = 0
do
local _item_0 = chain
for _index_0 = 3, #_item_0 do
local item = _item_0[_index_0]
_len_0 = _len_0 + 1
_accum_0[_len_0] = item
end
end
return _accum_0
end)()
slice[1] = {
"call",
{
"self",
unpack(slice[1][2])
}
}
local act
if ntype(calling_name) ~= "value" then
act = "index"
else
act = "dot"
end
return {
"chain",
parent_loc,
{
act,
calling_name
},
unpack(slice)
}
end)
local base_name = _with_0:init_free_var("base", tbl)
_with_0:stm({
"assign",
{
{
"chain",
base_name,
{
"dot",
"__index"
}
}
},
{
base_name
}
})
_with_0:stm({
"if",
parent_loc,
{
{
"chain",
"setmetatable",
{
"call",
{
base_name,
{
"chain",
"getmetatable",
{
"call",
{
parent_loc
}
},
{
"dot",
"__index"
}
}
}
}
}
}
})
local cls = {
"table",
{
{
"__init",
constructor
}
}
}
local cls_mt = {
"table",
{
{
"__index",
base_name
},
{
"__call",
{
"fndef",
{
{
"mt"
},
{
"..."
}
},
{ },
"slim",
{
{
"raw",
("local self = setmetatable({}, %s)"):format(base_name)
},
{
"chain",
"mt.__init",
{
"call",
{
"self",
"..."
}
}
},
"self"
}
}
}
}
}
local cls_name = _with_0:init_free_var("class", {
"chain",
"setmetatable",
{
"call",
{
cls,
cls_mt
}
}
})
_with_0:stm({
"assign",
{
{
"chain",
base_name,
{
"dot",
"__class"
}
}
},
{
cls_name
}
})
_with_0:stm({
"return",
cls_name
})
def_scope = _with_0
end
self:stm({
"declare",
{
name
}
})
return self:line(name, " = ", def_scope)
end,
comprehension = function(self, node, action)
local _, exp, clauses = unpack(node)
if not action then
@ -698,5 +468,12 @@ line_compile = {
end
return _with_0
end
end,
run = function(self, code)
code:call(self)
return nil
end,
group = function(self, node)
return self:stms(node[2])
end
}

View File

@ -48,14 +48,17 @@ line_compile =
i = i +1
with @line!
skip_values = false
if #undeclared == #names and not has_fndef
\append declare
skip_values = true if #values == 0
else
@add declare if #undeclared > 0
\append_list [@value name for name in *names], ", "
\append " = "
\append_list [@value v for v in *values], ", "
if not skip_values
\append " = "
\append_list [@value v for v in *values], ", "
update: (node) =>
_, name, op, exp = unpack node
@ -197,90 +200,6 @@ line_compile =
@declare names
nil
class: (node) =>
_, name, parent_val, tbl = unpack node
constructor = nil
final_properties = {}
-- organize constructor and everything else
for entry in *tbl[2]
if entry[1] == constructor_name
constructor = entry[2]
else
insert final_properties, entry
tbl[2] = final_properties
-- now create the class's initialization block
parent_loc = @free_name "parent", true
-- synthesize constructor if needed
if not constructor
constructor = {"fndef", {{"..."}}, {}, "fat", {
{"if", parent_loc, {
{"chain", "super", {"call", {"..."}}}
}}
}}
smart_node constructor
constructor.arrow = "fat"
def_scope = with @block!
parent_val = @value parent_val if parent_val != ""
\put_name parent_loc
.header = @line "(function(", parent_loc, ")"
.footer = @line "end)(", parent_val, ")"
\set "super", (block, chain) ->
calling_name = block\get"current_block"
slice = [item for item in *chain[3:]]
-- inject self
slice[1] = {"call", {"self", unpack slice[1][2]}}
act = if ntype(calling_name) != "value" then "index" else "dot"
{"chain", parent_loc, {act, calling_name}, unpack slice}
-- the metatable holding all the class methods
base_name = \init_free_var "base", tbl
\stm {"assign", { {"chain", base_name, {"dot", "__index"}} }, { base_name }}
-- handle super class if there is one
\stm {"if", parent_loc,
{{"chain", "setmetatable", {"call",
{base_name, {"chain", "getmetatable",
{"call", {parent_loc}}, {"dot", "__index"}}}}}}}
-- the class object that is returned
cls = {"table", {
{"__init", constructor}
}}
-- the class's meta table, gives us call and access to base methods
cls_mt = {"table", {
{"__index", base_name}
{"__call", {"fndef", {{"mt"}, {"..."}}, {}, "slim", {
{"raw", ("local self = setmetatable({}, %s)")\format(base_name)}
{"chain", "mt.__init", {"call", {"self", "..."}}}
"self"
}}}
}}
cls_name = \init_free_var "class", {
"chain", "setmetatable", {"call", {cls, cls_mt}}
}
\stm {"assign"
{{"chain", base_name, {"dot", "__class"}}}
{cls_name}
}
\stm {"return", cls_name}
@stm {"declare", {name}}
@line name, " = ", def_scope
comprehension: (node, action) =>
_, exp, clauses = unpack node
@ -312,3 +231,10 @@ line_compile =
\stms block
\stm ret var if ret
run: (code) =>
code\call self
nil
group: (node) =>
@stms node[2]

View File

@ -2,7 +2,8 @@ module("moonscript.transform", package.seeall)
local types = require("moonscript.types")
local util = require("moonscript.util")
local data = require("moonscript.data")
local ntype, build = types.ntype, types.build
local ntype, build, smart_node = types.ntype, types.build, types.smart_node
local insert = table.insert
NameProxy = (function(_parent_0)
local _base_0 = {
get_name = function(self, scope)
@ -11,6 +12,39 @@ NameProxy = (function(_parent_0)
end
return self.name
end,
chain = function(self, ...)
local items = {
...
}
items = (function()
local _accum_0 = { }
local _len_0 = 0
do
local _item_0 = items
for _index_0 = 1, #_item_0 do
local i = _item_0[_index_0]
local _value_0
if type(i) == "string" then
_value_0 = {
"dot",
i
}
else
_value_0 = i
end
if _value_0 ~= nil then
_len_0 = _len_0 + 1
_accum_0[_len_0] = _value_0
end
end
end
return _accum_0
end)()
return build.chain({
base = self,
unpack(items)
})
end,
__tostring = function(self)
if self.name then
return ("name<%s>"):format(self.name)
@ -39,7 +73,244 @@ NameProxy = (function(_parent_0)
_base_0.__class = _class_0
return _class_0
end)()
local Run
Run = (function(_parent_0)
local _base_0 = {
call = function(self, state)
return self.fn(state)
end
}
_base_0.__index = _base_0
if _parent_0 then
setmetatable(_base_0, getmetatable(_parent_0).__index)
end
local _class_0 = setmetatable({
__init = function(self, fn)
self.fn = fn
self[1] = "run"
end
}, {
__index = _base_0,
__call = function(mt, ...)
local self = setmetatable({}, _base_0)
mt.__init(self, ...)
return self
end
})
_base_0.__class = _class_0
return _class_0
end)()
local constructor_name = "new"
local transformers = {
class = function(node)
local _, name, parent_val, tbl = unpack(node)
local constructor = nil
local properties = (function()
local _accum_0 = { }
local _len_0 = 0
do
local _item_0 = tbl[2]
for _index_0 = 1, #_item_0 do
local entry = _item_0[_index_0]
local _value_0
if entry[1] == constructor_name then
constructor = entry[2]
_value_0 = nil
else
_value_0 = entry
end
if _value_0 ~= nil then
_len_0 = _len_0 + 1
_accum_0[_len_0] = _value_0
end
end
end
return _accum_0
end)()
tbl[2] = properties
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
constructor = build.fndef({
args = {
{
"..."
}
},
arrow = "fat",
body = {
build["if"]({
cond = parent_cls_name,
["then"] = {
build.chain({
base = "super",
{
"call",
{
"..."
}
}
})
}
})
}
})
else
smart_node(constructor)
constructor.arrow = "fat"
end
local cls = build.table({
{
"__init",
constructor
}
})
local cls_mt = build.table({
{
"__index",
base_name
},
{
"__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 _with_0 = build
value = _with_0.block_exp({
Run(function(self)
return self:set("super", function(block, chain)
local calling_name = block:get("current_block")
local slice = (function()
local _accum_0 = { }
local _len_0 = 0
do
local _item_0 = chain
for _index_0 = 3, #_item_0 do
local item = _item_0[_index_0]
_len_0 = _len_0 + 1
_accum_0[_len_0] = item
end
end
return _accum_0
end)()
slice[1] = {
"call",
{
"self",
unpack(slice[1][2])
}
}
local act
if ntype(calling_name) ~= "value" then
act = "index"
else
act = "dot"
end
return {
"chain",
parent_cls_name,
{
act,
calling_name
},
unpack(slice)
}
end)
end),
_with_0.assign_one(parent_cls_name, parent_val == "" and "nil" or parent_val),
_with_0.assign_one(base_name, tbl),
_with_0.assign_one(base_name:chain("__index"), base_name),
build["if"]({
cond = parent_cls_name,
["then"] = {
_with_0.chain({
base = "setmetatable",
{
"call",
{
base_name,
_with_0.chain({
base = "getmetatable",
{
"call",
{
parent_cls_name
}
},
{
"dot",
"__index"
}
})
}
}
})
}
}),
_with_0.assign_one(cls_name, cls),
_with_0.assign_one(base_name:chain("__class"), cls_name),
cls_name
})
value = _with_0.group({
_with_0.assign_one(name),
_with_0.assign({
names = {
name
},
values = {
value
}
})
})
end
return value
end,
chain = function(node)
local stub = node[#node]
if type(stub) == "table" and stub[1] == "colon_stub" then

View File

@ -5,7 +5,8 @@ types = require "moonscript.types"
util = require "moonscript.util"
data = require "moonscript.data"
import ntype, build from types
import ntype, build, smart_node from types
import insert from table
export node, NameProxy
@ -18,13 +19,144 @@ class NameProxy
@name = scope\free_name @prefix, true
@name
chain: (...) =>
items = {...} -- todo: fix ... propagation
items = for i in *items
if type(i) == "string"
{"dot", i}
else
i
build.chain {
base: self
unpack items
}
__tostring: =>
if @name
("name<%s>")\format @name
else
("name<prefix(%s)>")\format @prefix
class Run
new: (@fn) =>
self[1] = "run"
call: (state) =>
self.fn state
constructor_name = "new"
transformers = {
class: (node) ->
_, name, parent_val, tbl = unpack node
constructor = nil
properties = for entry in *tbl[2]
if entry[1] == constructor_name
constructor = entry[2]
nil
else
entry
tbl[2] = properties
parent_cls_name = NameProxy "parent"
base_name = NameProxy "base"
self_name = NameProxy "self"
cls_name = NameProxy "class"
if not constructor
constructor = build.fndef {
args: {{"..."}}
arrow: "fat"
body: {
build["if"] {
cond: parent_cls_name
then: {
build.chain { base: "super", {"call", {"..."}} }
}
}
}
}
else
smart_node constructor
constructor.arrow = "fat"
cls = build.table {
{"__init", constructor}
}
cls_mt = build.table {
{"__index", base_name}
{"__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
value = .block_exp {
Run =>
@set "super", (block, chain) ->
calling_name = block\get"current_block"
slice = [item for item in *chain[3:]]
-- inject self
slice[1] = {"call", {"self", unpack slice[1][2]}}
act = if ntype(calling_name) != "value" then "index" else "dot"
{"chain", parent_cls_name, {act, calling_name}, unpack slice}
.assign_one parent_cls_name, parent_val == "" and "nil" or parent_val
.assign_one base_name, tbl
.assign_one base_name\chain"__index", base_name
build["if"] {
cond: parent_cls_name
then: {
.chain {
base: "setmetatable"
{"call", {base_name, .chain {
base: "getmetatable"
{"call", {parent_cls_name}}
{"dot", "__index"}
}}}
}
}
}
.assign_one cls_name, cls
.assign_one base_name\chain"__class", cls_name
cls_name
}
value = .group {
.assign_one name
.assign {
names: {name}
values: {value}
}
}
value
-- pull out colon chain
chain: (node) ->
stub = node[#node]

View File

@ -38,6 +38,16 @@ local node_types = {
"values",
t
}
},
["if"] = {
{
"cond",
t
},
{
"then",
t
}
}
}
local build_table
@ -85,6 +95,28 @@ make_builder = function(name)
end
build = nil
build = setmetatable({
group = function(body)
return {
"group",
body
}
end,
assign_one = function(name, value)
return build.assign({
names = {
name
},
values = {
value
}
})
end,
table = function(tbl)
return {
"table",
tbl
}
end,
block_exp = function(body)
local fn = build.fndef({
body = body

View File

@ -26,6 +26,10 @@ node_types = {
{"names", t}
{"values", t}
}
if: {
{"cond", t}
{"then", t}
}
}
build_table = ->
@ -55,6 +59,15 @@ make_builder = (name) ->
build = nil
build = setmetatable {
group: (body) ->
{"group", body}
assign_one: (name, value) ->
build.assign {
names: {name}
values: {value}
}
table: (tbl) ->
{"table", tbl}
block_exp: (body) ->
fn = build.fndef body: body
build.chain { base: {"parens", fn}, {"call", {}} }

View File

@ -1,5 +1,6 @@
local Hello
Hello = (function(_parent_0)
Hello = (function()
local _parent_0 = nil
local _base_0 = {
hello = function(self)
return print(self.test, self.world)
@ -19,10 +20,10 @@ Hello = (function(_parent_0)
end
}, {
__index = _base_0,
__call = function(mt, ...)
local self = setmetatable({}, _base_0)
mt.__init(self, ...)
return self
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
@ -32,7 +33,8 @@ local x = Hello(1, 2)
x:hello()
print(x)
local Simple
Simple = (function(_parent_0)
Simple = (function()
local _parent_0 = nil
local _base_0 = {
cool = function(self)
return print("cool")
@ -50,17 +52,18 @@ Simple = (function(_parent_0)
end
}, {
__index = _base_0,
__call = function(mt, ...)
local self = setmetatable({}, _base_0)
mt.__init(self, ...)
return self
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
return _class_0
end)()
local Yikes
Yikes = (function(_parent_0)
Yikes = (function()
local _parent_0 = Simple
local _base_0 = { }
_base_0.__index = _base_0
if _parent_0 then
@ -72,19 +75,20 @@ Yikes = (function(_parent_0)
end
}, {
__index = _base_0,
__call = function(mt, ...)
local self = setmetatable({}, _base_0)
mt.__init(self, ...)
return self
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
return _class_0
end)(Simple)
end)()
x = Yikes()
x:cool()
local Hi
Hi = (function(_parent_0)
Hi = (function()
local _parent_0 = nil
local _base_0 = {
cool = function(self, num)
return print("num", num)
@ -100,16 +104,18 @@ Hi = (function(_parent_0)
end
}, {
__index = _base_0,
__call = function(mt, ...)
local self = setmetatable({}, _base_0)
mt.__init(self, ...)
return self
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
return _class_0
end)()
Simple = (function(_parent_0)
Simple =
Simple = (function()
local _parent_0 = Hi
local _base_0 = {
cool = function(self)
return _parent_0.cool(self, 120302)
@ -125,20 +131,21 @@ Simple = (function(_parent_0)
end
}, {
__index = _base_0,
__call = function(mt, ...)
local self = setmetatable({}, _base_0)
mt.__init(self, ...)
return self
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
return _class_0
end)(Hi)
end)()
x = Simple()
x:cool()
print(x.__class == Simple)
local Okay
Okay = (function(_parent_0)
Okay = (function()
local _parent_0 = nil
local _base_0 = {
something = 20323
}
@ -154,10 +161,10 @@ Okay = (function(_parent_0)
end
}, {
__index = _base_0,
__call = function(mt, ...)
local self = setmetatable({}, _base_0)
mt.__init(self, ...)
return self
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0

3
todo
View File

@ -1,5 +1,8 @@
# TODO
- error with stray comma at end of line
- ugly error if attempting to assign to rvalue like #hello
- dump node in mark, see why values are being parsed multiple times
if hello else world