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 data = require("moonscript.data")
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 Stack, Set, ntype = data.Stack, data.Set, data.ntype
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 = {
exp = function(self, node)
local _comp
@ -697,7 +330,7 @@ build_compiler = function()
Block(nil)
return setmetatable({ }, { __index = compiler_index })
end
_M.tree = function(tree)
tree = function(tree)
local scope = Block()
local _item_0 = tree
for _index_0=1,#_item_0 do

View File

@ -1,299 +1,17 @@
module "moonscript.compile", package.seeall
util = require "moonscript.util"
data = require "moonscript.data"
dump = require "moonscript.dump"
require "moonscript.compile.format"
require "moonscript.compile.line"
import map, bind, itwos, every, reversed from util
import Stack, Set, ntype from data
import concat, insert from table
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)]
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?
export tree
value_compile =
exp: (node) =>
@ -566,7 +284,7 @@ build_compiler = ->
Block(nil)
setmetatable {}, { __index: compiler_index }
_M.tree = (tree) ->
tree = (tree) ->
scope = Block()
scope:stm line for line in *tree
scope:render()

View File

@ -227,7 +227,7 @@ local build_grammar = wrap(function()
Block = Ct(Line * (Break^1 * Line)^0),
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
key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" +
CompInner / mark"comprehension"
@ -340,6 +340,10 @@ local build_grammar = wrap(function()
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)),
KeyValueList = KeyValue * (sym"," * KeyValue)^0,
KeyValueLine = Cmt(Indent, check_indent) * KeyValueList * sym","^-1,
@ -371,7 +375,20 @@ local build_grammar = wrap(function()
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
local line_no = pos_to_line(last_pos)
local line_str = get_line(line_no)