split compiler across multiple files

This commit is contained in:
leaf corcoran 2011-06-14 09:28:28 -07:00
parent f133f263b4
commit c6aa90bcbc
7 changed files with 733 additions and 659 deletions

View File

@ -0,0 +1,70 @@
module("moonscript.compile", package.seeall)
local util = require("moonscript.util")
local data = require("moonscript.data")
local itwos = util.itwos
local Set, ntype = data.Set, data.ntype
local concat, insert = table.concat, table.insert
indent_char = " "
pretty = function(lines, indent)
indent = indent or ""
local render
render = function(line)
if type(line) == "table" then
return indent_char .. pretty(line, indent .. indent_char)
else
return line
end
end
lines = (function()
local _moon_0 = {}
local _item_0 = lines
for _index_0=1,#_item_0 do
local line = _item_0[_index_0]
table.insert(_moon_0, render(line))
end
return _moon_0
end)()
local fix
fix = function(i, left, k, right)
if left:sub(-1) == ")" and right:sub(1, 1) == "(" then
lines[i] = lines[i] .. ";"
end
end
for i, l, k, r in itwos(lines) do
fix(i, l, k, r)
end
return concat(lines, "\n" .. indent)
end
returner = function(exp)
if ntype(exp) == "chain" and exp[2] == "return" then
local items = { "explist" }
local _item_0 = exp[3][2]
for _index_0=1,#_item_0 do
local v = _item_0[_index_0]
insert(items, v)
end
return { "return", items }
else
return { "return", exp }
end
end
moonlib = { bind = function(tbl, name) return concat({
"moon.bind(",
tbl,
".",
name,
", ",
tbl,
")"
}) end }
cascading = Set({ "if" })
non_atomic = Set({ "update" })
has_value = function(node)
if ntype(node) == "chain" then
local ctype = ntype(node[#node])
return ctype ~= "call" and ctype ~= "colon"
else
return true
end
end
is_non_atomic = function(node) return non_atomic[ntype(node)] end

View File

@ -0,0 +1,58 @@
module "moonscript.compile", package.seeall
util = require "moonscript.util"
data = require "moonscript.data"
import itwos from util
import Set, ntype from data
import concat, insert from table
export indent_char, pretty, returner, moonlib, cascading, non_atomic, has_value, is_non_atomic
indent_char = " "
pretty = (lines, indent) ->
indent = indent or ""
render = (line) ->
if type(line) == "table"
indent_char..pretty(line, indent..indent_char)
else
line
lines = [render line for line in *lines]
-- add semicolons for ambiguities
fix = (i, left, k, right) ->
if left:sub(-1) == ")" and right:sub(1,1) == "("
lines[i] = lines[i]..";"
fix(i,l, k,r) for i,l,k,r in itwos lines
concat lines, "\n"..indent
returner = (exp) ->
if ntype(exp) == "chain" and exp[2] == "return"
-- extract the return
items = {"explist"}
insert items, v for v in *exp[3][2]
{"return", items}
else
{"return", exp}
moonlib =
bind: (tbl, name) ->
concat {"moon.bind(", tbl, ".", name, ", ", tbl, ")"}
cascading = Set{ "if" }
-- an action that can't be completed in a single line
non_atomic = Set{ "update" }
-- does this always return a value
has_value = (node) ->
if ntype(node) == "chain"
ctype = ntype(node[#node])
ctype != "call" and ctype != "colon"
else
true
is_non_atomic = (node) ->
non_atomic[ntype(node)]

320
moonscript/compile/line.lua Normal file
View File

@ -0,0 +1,320 @@
module("moonscript.compile", package.seeall)
local util = require("moonscript.util")
local data = require("moonscript.data")
local dump = require("moonscript.dump")
require("moonscript.compile.format")
local reversed = util.reversed
local ntype = data.ntype
local concat, insert = table.concat, table.insert
line_compile = {
assign = function(self, node)
local _, names, values = unpack(node)
local undeclared = self:declare(names)
local declare = "local " .. (concat(undeclared, ", "))
if self:is_stm(values) then
if #undeclared > 0 then
self:add_line(declare)
end
if cascading[ntype(values)] then
local decorate
decorate = function(value) return { "assign", names, { value } } end
return self:stm(values, decorate)
else
return self:add_line(concat((function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local n = _item_0[_index_0]
table.insert(_moon_0, self:value(n))
end
return _moon_0
end)(), ", ") .. " = " .. self:value(values))
end
else
local has_fndef = false
local i = 1
while i <= #values do
if ntype(values[i]) == "fndef" then
has_fndef = true
end
i = i + 1
end
values = concat((function()
local _moon_0 = {}
local _item_0 = values
for _index_0=1,#_item_0 do
local v = _item_0[_index_0]
table.insert(_moon_0, self:value(v))
end
return _moon_0
end)(), ", ")
if #undeclared == #names and not has_fndef then
return self:add_line(declare .. ' = ' .. values)
else
if #undeclared > 0 then
self:add_line(declare)
end
return self:add_line(concat((function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local n = _item_0[_index_0]
table.insert(_moon_0, self:value(n))
end
return _moon_0
end)(), ", ") .. " = " .. values)
end
end
end,
update = function(self, node)
local _, name, op, exp = unpack(node)
local op_final = op:match("(.)=")
if not op_final then
_ = error("unknown op: ") .. op
end
return self:stm({ "assign", { name }, { {
"exp",
name,
op_final,
exp
} } })
end,
["return"] = function(self, node) return self:add_line("return", self:value(node[2])) end,
["break"] = function(self, node) return self:add_line("break") end,
["import"] = function(self, node)
local _, names, source = unpack(node)
local to_bind = { }
local get_name
get_name = function(name)
if ntype(name) == ":" then
local tmp = self:name(name[2])
to_bind[tmp] = true
return tmp
else
return self:name(name)
end
end
local final_names = (function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local n = _item_0[_index_0]
table.insert(_moon_0, get_name(n))
end
return _moon_0
end)()
local _item_0 = final_names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
self:put_name(name)
end
local get_value
get_value = function(name)
if to_bind[name] then
return moonlib.bind(source, name)
else
return source .. "." .. name
end
end
if type(source) == "string" then
local values = (function()
local _moon_0 = {}
local _item_0 = final_names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
table.insert(_moon_0, get_value(name))
end
return _moon_0
end)()
self:add_line("local", (concat(final_names, ", ")), "=", (concat(values, ", ")))
return(nil)
end
self:add_line("local", concat(final_names, ", "))
self:add_line("do")
local inner = self:block()
local tmp_name = inner:free_name("table")
inner:add_line("local", tmp_name, "=", self:value(source))
source = tmp_name
local _item_0 = final_names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
inner:add_line(name .. " = " .. get_value(name))
end
self:add_line(inner:render())
return self:add_line("end")
end,
["if"] = function(self, node, ret)
local cond, block = node[2], node[3]
local add_clause
add_clause = function(clause)
local type = clause[1]
if type == "else" then
self:add_line("else")
block = clause[2]
else
self:add_line("elseif", (self:value(clause[2])), "then")
block = clause[3]
end
local b = self:block()
b:stms(block, ret)
return self:add_line(b:render())
end
self:add_line("if", (self:value(cond)), "then")
local b = self:block()
b:stms(block, ret)
self:add_line(b:render())
for i, cond in ipairs(node) do
if i > 3 then
add_clause(cond)
end
end
return self:add_line("end")
end,
["while"] = function(self, node)
local _, cond, block = unpack(node)
local inner = self:block()
if is_non_atomic(cond) then
self:add_line("while", "true", "do")
inner:stm({ "if", { "not", cond }, { { "break" } } })
else
self:add_line("while", self:value(cond), "do")
end
inner:stms(block)
self:add_line(inner:render())
return self:add_line("end")
end,
["for"] = function(self, node)
local _, name, bounds, block = unpack(node)
bounds = self:value({ "explist", unpack(bounds) })
self:add_line("for", self:name(name), "=", bounds, "do")
local inner = self:block()
inner:stms(block)
self:add_line(inner:render())
return self:add_line("end")
end,
["export"] = function(self, node)
local _, names = unpack(node)
local _item_0 = names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
if type(name) == "string" then
self:put_name(name)
end
end
return nil
end,
["class"] = function(self, node)
local _, name, table = unpack(node)
local mt_name = "_" .. name .. "_mt"
self:add_line("local", concat(self:declare({ name, mt_name }), ", "))
local constructor = nil
local meta_methods = { }
local final_properties = { }
local overloaded_index = value
local find_special
find_special = function(name, value)
if name == "constructor" then
constructor = value
elseif name:match("^__%a") then
insert(meta_methods, { name, value })
if name == "__index" then
overloaded_index = value
end
else
return insert(final_properties, { name, value })
end
end
local _item_0 = table[2]
for _index_0=1,#_item_0 do
local entry = _item_0[_index_0]
find_special(unpack(entry))
end
if not overloaded_index then
insert(meta_methods, { "__index", { "table", final_properties } })
end
print(util.dump(constructor))
print(util.dump(meta_methods))
print(util.dump(final_properties))
self:stm({ "assign", { mt_name }, { { "table", meta_methods } } })
if not constructor then
constructor = {
"fndef",
{ },
"slim",
{ }
}
end
local self_args = { }
local get_initializers
get_initializers = function(arg)
if ntype(arg) == "self" then
arg = arg[2]
insert(self_args, arg)
end
return arg
end
constructor[2] = (function()
local _moon_0 = {}
local _item_0 = constructor[2]
for _index_0=1,#_item_0 do
local arg = _item_0[_index_0]
table.insert(_moon_0, get_initializers(arg))
end
return _moon_0
end)()
print(util.dump(constructor))
return self:stm({ "assign", { name }, { constructor } })
end,
comprehension = function(self, node, action)
local _, exp, clauses = unpack(node)
if not action then
action = self:block()
action:stm(exp)
end
local depth = #clauses
action:set_indent(self.indent + depth)
local render_clause
render_clause = function(self, clause)
local t = clause[1]
action = self:block()
action:set_indent(-1 + self.indent)
if "for" == t then
local names, iter
_, names, iter = unpack(clause)
local name_list = concat((function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
table.insert(_moon_0, self:name(name))
end
return _moon_0
end)(), ", ")
if ntype(iter) == "unpack" then
iter = iter[2]
local items_tmp = self:free_name("item")
local index_tmp = self:free_name("index")
insert(self._lines, 1, ("local %s = %s[%s]"):format(name_list, items_tmp, index_tmp))
return action:add_lines({
("local %s = %s"):format(items_tmp, self:value(iter)),
("for %s=1,#%s do"):format(index_tmp, items_tmp),
self:render(true),
"end"
})
else
return action:add_lines({ ("for %s in %s do"):format(name_list, self:value(iter)), self:render(true), "end" })
end
elseif "when" == t then
local cond
_, cond = unpack(clause)
return action:add_lines({ ("if %s then"):format(self:value(cond)), self:render(true), "end" })
else
return error("Unknown comprehension clause: " .. t)
end
end
for i, clause in reversed(clauses) do
render_clause(action, clause)
end
return self:add_lines(action._lines)
end
}

View File

@ -0,0 +1,258 @@
module "moonscript.compile", package.seeall
util = require "moonscript.util"
data = require "moonscript.data"
dump = require "moonscript.dump"
require "moonscript.compile.format"
import reversed from util
import ntype from data
import concat, insert from table
export line_compile
line_compile =
assign: (node) =>
_, names, values = unpack node
undeclared = @declare names
declare = "local "..(concat undeclared, ", ")
if @is_stm values
@add_line declare if #undeclared > 0
if cascading[ntype(values)]
decorate = (value) ->
{"assign", names, {value}}
@stm values, decorate
else
@add_line concat([@value n for n in *names], ", ").." = "..@value values
else
has_fndef = false
i = 1
while i <= #values
if ntype(values[i]) == "fndef"
has_fndef = true
i = i +1
-- need new compiler
-- (if ntype(v) == "fndef" then has_fndef = true) for v in *values
values = concat [@value v for v in *values], ", "
if #undeclared == #names and not has_fndef
@add_line declare..' = '..values
else
@add_line declare if #undeclared > 0
@add_line concat([@value n for n in *names], ", ").." = "..values
update: (node) =>
_, name, op, exp = unpack node
op_final = op:match"(.)="
error"unknown op: "..op if not op_final
@stm {"assign", {name}, {{"exp", name, op_final, exp}}}
["return"]: (node) =>
@add_line "return", @value node[2]
["break"]: (node) =>
@add_line "break"
["import"]: (node) =>
_, names, source = unpack node
to_bind = {}
get_name = (name) ->
if ntype(name) == ":"
tmp = @name name[2]
to_bind[tmp] = true
tmp
else
@name name
final_names = [get_name n for n in *names]
@put_name name for name in *final_names
get_value = (name) ->
if to_bind[name]
moonlib.bind source, name
else
source.."."..name
-- from constant expression, put it on one line
if type(source) == "string"
values = [get_value name for name in *final_names]
@add_line "local", (concat final_names, ", "), "=", (concat values, ", ")
return nil
@add_line "local", concat(final_names, ", ")
@add_line "do"
inner = @block()
tmp_name = inner:free_name "table"
inner:add_line "local", tmp_name , "=", @value source
source = tmp_name
inner:add_line name.." = "..get_value name for name in *final_names
@add_line inner:render()
@add_line "end"
["if"]: (node, ret) =>
cond, block = node[2], node[3]
add_clause = (clause) ->
type = clause[1]
block = if type == "else"
@add_line "else"
clause[2]
else
@add_line "elseif", (@value clause[2]), "then"
clause[3]
b = @block()
b:stms block, ret
@add_line b:render()
@add_line "if", (@value cond), "then"
b = @block()
b:stms block, ret
@add_line b:render()
add_clause cond for i, cond in ipairs node when i > 3
@add_line "end"
["while"]: (node) =>
_, cond, block = unpack node
inner = @block()
if is_non_atomic cond
@add_line "while", "true", "do"
inner:stm {"if", {"not", cond}, {{"break"}}}
else
@add_line "while", @value(cond), "do"
inner:stms block
@add_line inner:render()
@add_line "end"
["for"]: (node) =>
_, name, bounds, block = unpack node
bounds = @value {"explist", unpack bounds}
@add_line "for", @name(name), "=", bounds, "do"
inner = @block()
inner:stms block
@add_line inner:render()
@add_line "end"
["export"]: (node) =>
_, names = unpack node
@put_name name for name in *names when type(name) == "string"
nil
["class"]: (node) =>
_, name, table = unpack node
mt_name = "_"..name.."_mt"
@add_line "local", concat @declare({ name, mt_name }), ", "
constructor = nil
meta_methods = {}
final_properties = {}
overloaded_index = value
find_special = (name, value) ->
if name == "constructor"
constructor = value
elseif name:match("^__%a")
insert meta_methods, {name, value}
overloaded_index = value if name == "__index"
else
insert final_properties, {name, value}
find_special unpack entry for entry in *table[2]
if not overloaded_index
insert meta_methods, {"__index", {"table", final_properties}}
print util.dump constructor
print util.dump meta_methods
print util.dump final_properties
@stm {"assign", {mt_name}, {{"table", meta_methods}}}
-- synthesize constructor
if not constructor
constructor = {"fndef", {}, "slim", {}}
-- extract self arguments
self_args = {}
get_initializers = (arg) ->
if ntype(arg) == "self"
arg = arg[2]
insert self_args, arg
arg
constructor[2] = [get_initializers arg for arg in *constructor[2]]
print util.dump constructor
@stm {"assign", {name}, {constructor}}
comprehension: (node, action) =>
_, exp, clauses = unpack node
if not action
action = @block()
action:stm exp
depth = #clauses
action:set_indent @indent + depth
render_clause = (clause) =>
t = clause[1]
action = @block()
action:set_indent -1 + @indent
if "for" == t
_, names, iter = unpack clause
name_list = concat [@name name for name in *names], ", "
if ntype(iter) == "unpack"
iter = iter[2]
items_tmp = @free_name "item"
index_tmp = @free_name "index"
insert self._lines, 1, ("local %s = %s[%s]"):format name_list, items_tmp, index_tmp
action:add_lines {
("local %s = %s"):format items_tmp, @value iter
("for %s=1,#%s do"):format index_tmp, items_tmp
@render true
"end"
}
else
action:add_lines {
("for %s in %s do"):format(name_list, @value iter)
@render true
"end"
}
elseif "when" == t
_, cond = unpack clause
action:add_lines {
("if %s then"):format @value cond
@render true
"end"
}
else
error "Unknown comprehension clause: "..t
render_clause action, clause for i, clause in reversed clauses
@add_lines action._lines -- do this better?

View File

@ -2,378 +2,11 @@ module("moonscript.compile", package.seeall)
local util = require("moonscript.util") local util = require("moonscript.util")
local data = require("moonscript.data") local data = require("moonscript.data")
local dump = require("moonscript.dump") local dump = require("moonscript.dump")
require("moonscript.compile.format")
require("moonscript.compile.line")
local map, bind, itwos, every, reversed = util.map, util.bind, util.itwos, util.every, util.reversed local map, bind, itwos, every, reversed = util.map, util.bind, util.itwos, util.every, util.reversed
local Stack, Set, ntype = data.Stack, data.Set, data.ntype local Stack, Set, ntype = data.Stack, data.Set, data.ntype
local concat, insert = table.concat, table.insert local concat, insert = table.concat, table.insert
local indent_char = " "
local pretty
pretty = function(lines, indent)
indent = indent or ""
local render
render = function(line)
if type(line) == "table" then
return indent_char .. pretty(line, indent .. indent_char)
else
return line
end
end
lines = (function()
local _moon_0 = {}
local _item_0 = lines
for _index_0=1,#_item_0 do
local line = _item_0[_index_0]
table.insert(_moon_0, render(line))
end
return _moon_0
end)()
local fix
fix = function(i, left, k, right)
if left:sub(-1) == ")" and right:sub(1, 1) == "(" then
lines[i] = lines[i] .. ";"
end
end
for i, l, k, r in itwos(lines) do
fix(i, l, k, r)
end
return concat(lines, "\n" .. indent)
end
local returner
returner = function(exp)
if ntype(exp) == "chain" and exp[2] == "return" then
local items = { "explist" }
local _item_0 = exp[3][2]
for _index_0=1,#_item_0 do
local v = _item_0[_index_0]
insert(items, v)
end
return { "return", items }
else
return { "return", exp }
end
end
local moonlib = { bind = function(tbl, name) return concat({
"moon.bind(",
tbl,
".",
name,
", ",
tbl,
")"
}) end }
local cascading = Set({ "if" })
local non_atomic = Set({ "update" })
local has_value
has_value = function(node)
if ntype(node) == "chain" then
local ctype = ntype(node[#node])
return ctype ~= "call" and ctype ~= "colon"
else
return true
end
end
local is_non_atomic
is_non_atomic = function(node) return non_atomic[ntype(node)] end
local line_compile = {
assign = function(self, node)
local _, names, values = unpack(node)
local undeclared = self:declare(names)
local declare = "local " .. (concat(undeclared, ", "))
if self:is_stm(values) then
if #undeclared > 0 then
self:add_line(declare)
end
if cascading[ntype(values)] then
local decorate
decorate = function(value) return { "assign", names, { value } } end
return self:stm(values, decorate)
else
return self:add_line(concat((function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local n = _item_0[_index_0]
table.insert(_moon_0, self:value(n))
end
return _moon_0
end)(), ", ") .. " = " .. self:value(values))
end
else
local has_fndef = false
local i = 1
while i <= #values do
if ntype(values[i]) == "fndef" then
has_fndef = true
end
i = i + 1
end
values = concat((function()
local _moon_0 = {}
local _item_0 = values
for _index_0=1,#_item_0 do
local v = _item_0[_index_0]
table.insert(_moon_0, self:value(v))
end
return _moon_0
end)(), ", ")
if #undeclared == #names and not has_fndef then
return self:add_line(declare .. ' = ' .. values)
else
if #undeclared > 0 then
self:add_line(declare)
end
return self:add_line(concat((function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local n = _item_0[_index_0]
table.insert(_moon_0, self:value(n))
end
return _moon_0
end)(), ", ") .. " = " .. values)
end
end
end,
update = function(self, node)
local _, name, op, exp = unpack(node)
local op_final = op:match("(.)=")
if not op_final then
_ = error("unknown op: ") .. op
end
return self:stm({ "assign", { name }, { {
"exp",
name,
op_final,
exp
} } })
end,
["return"] = function(self, node) return self:add_line("return", self:value(node[2])) end,
["break"] = function(self, node) return self:add_line("break") end,
["import"] = function(self, node)
local _, names, source = unpack(node)
local to_bind = { }
local get_name
get_name = function(name)
if ntype(name) == ":" then
local tmp = self:name(name[2])
to_bind[tmp] = true
return tmp
else
return self:name(name)
end
end
local final_names = (function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local n = _item_0[_index_0]
table.insert(_moon_0, get_name(n))
end
return _moon_0
end)()
local _item_0 = final_names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
self:put_name(name)
end
local get_value
get_value = function(name)
if to_bind[name] then
return moonlib.bind(source, name)
else
return source .. "." .. name
end
end
if type(source) == "string" then
local values = (function()
local _moon_0 = {}
local _item_0 = final_names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
table.insert(_moon_0, get_value(name))
end
return _moon_0
end)()
self:add_line("local", (concat(final_names, ", ")), "=", (concat(values, ", ")))
return(nil)
end
self:add_line("local", concat(final_names, ", "))
self:add_line("do")
local inner = self:block()
local tmp_name = inner:free_name("table")
inner:add_line("local", tmp_name, "=", self:value(source))
source = tmp_name
local _item_0 = final_names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
inner:add_line(name .. " = " .. get_value(name))
end
self:add_line(inner:render())
return self:add_line("end")
end,
["if"] = function(self, node, ret)
local cond, block = node[2], node[3]
local add_clause
add_clause = function(clause)
local type = clause[1]
if type == "else" then
self:add_line("else")
block = clause[2]
else
self:add_line("elseif", (self:value(clause[2])), "then")
block = clause[3]
end
local b = self:block()
b:stms(block, ret)
return self:add_line(b:render())
end
self:add_line("if", (self:value(cond)), "then")
local b = self:block()
b:stms(block, ret)
self:add_line(b:render())
for i, cond in ipairs(node) do
if i > 3 then
add_clause(cond)
end
end
return self:add_line("end")
end,
["while"] = function(self, node)
local _, cond, block = unpack(node)
local inner = self:block()
if is_non_atomic(cond) then
self:add_line("while", "true", "do")
inner:stm({ "if", { "not", cond }, { { "break" } } })
else
self:add_line("while", self:value(cond), "do")
end
inner:stms(block)
self:add_line(inner:render())
return self:add_line("end")
end,
["for"] = function(self, node)
local _, name, bounds, block = unpack(node)
bounds = self:value({ "explist", unpack(bounds) })
self:add_line("for", self:name(name), "=", bounds, "do")
local inner = self:block()
inner:stms(block)
self:add_line(inner:render())
return self:add_line("end")
end,
["class"] = function(self, node)
local _, name, table = unpack(node)
local mt_name = "_" .. name .. "_mt"
self:add_line("local", concat(self:declare({ name, mt_name }), ", "))
local constructor = nil
local meta_methods = { }
local final_properties = { }
local overloaded_index = value
local find_special
find_special = function(name, value)
if name == "constructor" then
constructor = value
elseif name:match("^__%a") then
insert(meta_methods, { name, value })
if name == "__index" then
overloaded_index = value
end
else
return insert(final_properties, { name, value })
end
end
local _item_0 = table[2]
for _index_0=1,#_item_0 do
local entry = _item_0[_index_0]
find_special(unpack(entry))
end
if not overloaded_index then
insert(meta_methods, { "__index", { "table", final_properties } })
end
print(util.dump(constructor))
print(util.dump(meta_methods))
print(util.dump(final_properties))
self:stm({ "assign", { mt_name }, { { "table", meta_methods } } })
if not constructor then
constructor = {
"fndef",
{ },
"slim",
{ }
}
end
local self_args = { }
local get_initializers
get_initializers = function(arg)
if ntype(arg) == "self" then
arg = arg[2]
insert(self_args, arg)
end
return arg
end
constructor[2] = (function()
local _moon_0 = {}
local _item_0 = constructor[2]
for _index_0=1,#_item_0 do
local arg = _item_0[_index_0]
table.insert(_moon_0, get_initializers(arg))
end
return _moon_0
end)()
print(util.dump(constructor))
return self:stm({ "assign", { name }, { constructor } })
end,
comprehension = function(self, node, action)
local _, exp, clauses = unpack(node)
if not action then
action = self:block()
action:stm(exp)
end
local depth = #clauses
action:set_indent(self.indent + depth)
local render_clause
render_clause = function(self, clause)
local t = clause[1]
action = self:block()
action:set_indent(-1 + self.indent)
if "for" == t then
local names, iter
_, names, iter = unpack(clause)
local name_list = concat((function()
local _moon_0 = {}
local _item_0 = names
for _index_0=1,#_item_0 do
local name = _item_0[_index_0]
table.insert(_moon_0, self:name(name))
end
return _moon_0
end)(), ", ")
if ntype(iter) == "unpack" then
iter = iter[2]
local items_tmp = self:free_name("item")
local index_tmp = self:free_name("index")
insert(self._lines, 1, ("local %s = %s[%s]"):format(name_list, items_tmp, index_tmp))
return action:add_lines({
("local %s = %s"):format(items_tmp, self:value(iter)),
("for %s=1,#%s do"):format(index_tmp, items_tmp),
self:render(true),
"end"
})
else
return action:add_lines({ ("for %s in %s do"):format(name_list, self:value(iter)), self:render(true), "end" })
end
elseif "when" == t then
local cond
_, cond = unpack(clause)
return action:add_lines({ ("if %s then"):format(self:value(cond)), self:render(true), "end" })
else
return error("Unknown comprehension clause: " .. t)
end
end
for i, clause in reversed(clauses) do
render_clause(action, clause)
end
return self:add_lines(action._lines)
end
}
local value_compile = { local value_compile = {
exp = function(self, node) exp = function(self, node)
local _comp local _comp
@ -697,7 +330,7 @@ build_compiler = function()
Block(nil) Block(nil)
return setmetatable({ }, { __index = compiler_index }) return setmetatable({ }, { __index = compiler_index })
end end
_M.tree = function(tree) tree = function(tree)
local scope = Block() local scope = Block()
local _item_0 = tree local _item_0 = tree
for _index_0=1,#_item_0 do for _index_0=1,#_item_0 do

View File

@ -1,299 +1,17 @@
module "moonscript.compile", package.seeall module "moonscript.compile", package.seeall
util = require "moonscript.util" util = require "moonscript.util"
data = require "moonscript.data" data = require "moonscript.data"
dump = require "moonscript.dump" dump = require "moonscript.dump"
require "moonscript.compile.format"
require "moonscript.compile.line"
import map, bind, itwos, every, reversed from util import map, bind, itwos, every, reversed from util
import Stack, Set, ntype from data import Stack, Set, ntype from data
import concat, insert from table import concat, insert from table
indent_char = " " export tree
pretty = (lines, indent) ->
indent = indent or ""
render = (line) ->
if type(line) == "table"
indent_char..pretty(line, indent..indent_char)
else
line
lines = [render line for line in *lines]
-- add semicolons for ambiguities
fix = (i, left, k, right) ->
if left:sub(-1) == ")" and right:sub(1,1) == "("
lines[i] = lines[i]..";"
fix(i,l, k,r) for i,l,k,r in itwos lines
concat lines, "\n"..indent
returner = (exp) ->
if ntype(exp) == "chain" and exp[2] == "return"
-- extract the return
items = {"explist"}
insert items, v for v in *exp[3][2]
{"return", items}
else
{"return", exp}
moonlib =
bind: (tbl, name) ->
concat {"moon.bind(", tbl, ".", name, ", ", tbl, ")"}
cascading = Set{ "if" }
-- an action that can't be completed in a single line
non_atomic = Set{ "update" }
-- does this always return a value
has_value = (node) ->
if ntype(node) == "chain"
ctype = ntype(node[#node])
ctype != "call" and ctype != "colon"
else
true
is_non_atomic = (node) ->
non_atomic[ntype(node)]
line_compile =
assign: (node) =>
_, names, values = unpack node
undeclared = @declare names
declare = "local "..(concat undeclared, ", ")
if @is_stm values
@add_line declare if #undeclared > 0
if cascading[ntype(values)]
decorate = (value) ->
{"assign", names, {value}}
@stm values, decorate
else
@add_line concat([@value n for n in *names], ", ").." = "..@value values
else
has_fndef = false
i = 1
while i <= #values
if ntype(values[i]) == "fndef"
has_fndef = true
i = i +1
-- need new compiler
-- (if ntype(v) == "fndef" then has_fndef = true) for v in *values
values = concat [@value v for v in *values], ", "
if #undeclared == #names and not has_fndef
@add_line declare..' = '..values
else
@add_line declare if #undeclared > 0
@add_line concat([@value n for n in *names], ", ").." = "..values
update: (node) =>
_, name, op, exp = unpack node
op_final = op:match"(.)="
error"unknown op: "..op if not op_final
@stm {"assign", {name}, {{"exp", name, op_final, exp}}}
["return"]: (node) =>
@add_line "return", @value node[2]
["break"]: (node) =>
@add_line "break"
["import"]: (node) =>
_, names, source = unpack node
to_bind = {}
get_name = (name) ->
if ntype(name) == ":"
tmp = @name name[2]
to_bind[tmp] = true
tmp
else
@name name
final_names = [get_name n for n in *names]
@put_name name for name in *final_names
get_value = (name) ->
if to_bind[name]
moonlib.bind source, name
else
source.."."..name
-- from constant expression, put it on one line
if type(source) == "string"
values = [get_value name for name in *final_names]
@add_line "local", (concat final_names, ", "), "=", (concat values, ", ")
return nil
@add_line "local", concat(final_names, ", ")
@add_line "do"
inner = @block()
tmp_name = inner:free_name "table"
inner:add_line "local", tmp_name , "=", @value source
source = tmp_name
inner:add_line name.." = "..get_value name for name in *final_names
@add_line inner:render()
@add_line "end"
["if"]: (node, ret) =>
cond, block = node[2], node[3]
add_clause = (clause) ->
type = clause[1]
block = if type == "else"
@add_line "else"
clause[2]
else
@add_line "elseif", (@value clause[2]), "then"
clause[3]
b = @block()
b:stms block, ret
@add_line b:render()
@add_line "if", (@value cond), "then"
b = @block()
b:stms block, ret
@add_line b:render()
add_clause cond for i, cond in ipairs node when i > 3
@add_line "end"
["while"]: (node) =>
_, cond, block = unpack node
inner = @block()
if is_non_atomic cond
@add_line "while", "true", "do"
inner:stm {"if", {"not", cond}, {{"break"}}}
else
@add_line "while", @value(cond), "do"
inner:stms block
@add_line inner:render()
@add_line "end"
["for"]: (node) =>
_, name, bounds, block = unpack node
bounds = @value {"explist", unpack bounds}
@add_line "for", @name(name), "=", bounds, "do"
inner = @block()
inner:stms block
@add_line inner:render()
@add_line "end"
["class"]: (node) =>
_, name, table = unpack node
mt_name = "_"..name.."_mt"
@add_line "local", concat @declare({ name, mt_name }), ", "
constructor = nil
meta_methods = {}
final_properties = {}
overloaded_index = value
find_special = (name, value) ->
if name == "constructor"
constructor = value
elseif name:match("^__%a")
insert meta_methods, {name, value}
overloaded_index = value if name == "__index"
else
insert final_properties, {name, value}
find_special unpack entry for entry in *table[2]
if not overloaded_index
insert meta_methods, {"__index", {"table", final_properties}}
print util.dump constructor
print util.dump meta_methods
print util.dump final_properties
@stm {"assign", {mt_name}, {{"table", meta_methods}}}
-- synthesize constructor
if not constructor
constructor = {"fndef", {}, "slim", {}}
-- extract self arguments
self_args = {}
get_initializers = (arg) ->
if ntype(arg) == "self"
arg = arg[2]
insert self_args, arg
arg
constructor[2] = [get_initializers arg for arg in *constructor[2]]
print util.dump constructor
@stm {"assign", {name}, {constructor}}
comprehension: (node, action) =>
_, exp, clauses = unpack node
if not action
action = @block()
action:stm exp
depth = #clauses
action:set_indent @indent + depth
render_clause = (clause) =>
t = clause[1]
action = @block()
action:set_indent -1 + @indent
if "for" == t
_, names, iter = unpack clause
name_list = concat [@name name for name in *names], ", "
if ntype(iter) == "unpack"
iter = iter[2]
items_tmp = @free_name "item"
index_tmp = @free_name "index"
insert self._lines, 1, ("local %s = %s[%s]"):format name_list, items_tmp, index_tmp
action:add_lines {
("local %s = %s"):format items_tmp, @value iter
("for %s=1,#%s do"):format index_tmp, items_tmp
@render true
"end"
}
else
action:add_lines {
("for %s in %s do"):format(name_list, @value iter)
@render true
"end"
}
elseif "when" == t
_, cond = unpack clause
action:add_lines {
("if %s then"):format @value cond
@render true
"end"
}
else
error "Unknown comprehension clause: "..t
render_clause action, clause for i, clause in reversed clauses
@add_lines action._lines -- do this better?
value_compile = value_compile =
exp: (node) => exp: (node) =>
@ -566,7 +284,7 @@ build_compiler = ->
Block(nil) Block(nil)
setmetatable {}, { __index: compiler_index } setmetatable {}, { __index: compiler_index }
_M.tree = (tree) -> tree = (tree) ->
scope = Block() scope = Block()
scope:stm line for line in *tree scope:stm line for line in *tree
scope:render() scope:render()

View File

@ -227,7 +227,7 @@ local build_grammar = wrap(function()
Block = Ct(Line * (Break^1 * Line)^0), Block = Ct(Line * (Break^1 * Line)^0),
Line = Cmt(Indent, check_indent) * Statement + _Space * Comment, Line = Cmt(Indent, check_indent) * Statement + _Space * Comment,
Statement = (Import + While + For + BreakLoop + Ct(ExpList) / flatten_or_mark"explist" * Space) * ( Statement = (Import + While + For + Export + BreakLoop + Ct(ExpList) / flatten_or_mark"explist" * Space) * (
-- statement decorators -- statement decorators
key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" + key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" +
CompInner / mark"comprehension" CompInner / mark"comprehension"
@ -340,6 +340,10 @@ local build_grammar = wrap(function()
TableBlock = Break * #Cmt(Indent, advance_indent) * TableBlockInner * OutBlock / mark"table", TableBlock = Break * #Cmt(Indent, advance_indent) * TableBlockInner * OutBlock / mark"table",
ClassDecl = key"class" * Name * TableBlock / mark"class",
Export = key"export" * Ct(NameList) / mark"export",
KeyValue = Ct((Name + sym"[" * Exp * sym"]") * symx":" * (Exp + TableBlock)), KeyValue = Ct((Name + sym"[" * Exp * sym"]") * symx":" * (Exp + TableBlock)),
KeyValueList = KeyValue * (sym"," * KeyValue)^0, KeyValueList = KeyValue * (sym"," * KeyValue)^0,
KeyValueLine = Cmt(Indent, check_indent) * KeyValueList * sym","^-1, KeyValueLine = Cmt(Indent, check_indent) * KeyValueList * sym","^-1,
@ -371,7 +375,20 @@ local build_grammar = wrap(function()
end end
end end
local tree = self._g:match(str, ...)
local tree
local args = {...}
local pass, err = pcall(function()
tree = self._g:match(str, unpack(args))
end)
if not pass then
local line_no = pos_to_line(last_pos)
print("stopped at", line_no)
error(err)
end
if not tree then if not tree then
local line_no = pos_to_line(last_pos) local line_no = pos_to_line(last_pos)
local line_str = get_line(line_no) local line_str = get_line(line_no)