mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
moved value compile to own file + cleanup
This commit is contained in:
parent
56c3af06d2
commit
192df0ec08
@ -1,560 +0,0 @@
|
||||
|
||||
module("moonscript.compile", package.seeall)
|
||||
|
||||
local util = require "moonscript.util"
|
||||
local data = require "moonscript.data"
|
||||
|
||||
-- this doesn't work
|
||||
-- setmetatable(_M, {
|
||||
-- __call = setfenv(function(self, ...)
|
||||
-- compile(...)
|
||||
-- end, _G)
|
||||
-- })
|
||||
|
||||
local map, bind, itwos = util.map, util.bind, util.itwos
|
||||
local Stack, ntype = data.Stack, data.ntype
|
||||
|
||||
local indent_char = " "
|
||||
|
||||
-- number of newlines in string
|
||||
local function num_lines(str)
|
||||
local sum = 0
|
||||
for v in str:gmatch("[\n]") do
|
||||
sum = sum + 1
|
||||
end
|
||||
return sum
|
||||
end
|
||||
|
||||
-- small enough to fit on one line
|
||||
local function is_small(str)
|
||||
return num_lines(str) == 0 and #str < 40
|
||||
end
|
||||
|
||||
-- functions that can be inlined, or called from build in library
|
||||
local moonlib = {
|
||||
bind = function(tbl, name)
|
||||
return table.concat{"moon.bind(", tbl, ".",
|
||||
name, ", ", tbl, ")"}
|
||||
end
|
||||
}
|
||||
|
||||
-- these are always expressions, never statements, must be sent into temp variable
|
||||
local must_return = data.Set{ 'parens', 'exp', 'value', 'string', 'table', 'fndef', 'explist' }
|
||||
|
||||
-- these can't return a value, and must be munged
|
||||
local block_statements = data.Set{ 'if' }
|
||||
|
||||
-- make sure there are no block levels statements in expression
|
||||
local function validate_expression(block)
|
||||
-- need to annotate blocks? how do I know where expressions are
|
||||
end
|
||||
|
||||
local compiler_index = {
|
||||
push = function(self) self._scope:push{} end,
|
||||
pop = function(self) self._scope:pop() end,
|
||||
|
||||
indent = function(self, amount)
|
||||
self._indent = self._indent + amount
|
||||
end,
|
||||
|
||||
pretty = function(self, tbl, indent_front)
|
||||
local out = {}
|
||||
for _, line in ipairs(tbl) do
|
||||
if type(line) == "table" then
|
||||
self:indent(1)
|
||||
table.insert(out, indent_char..self:pretty(line))
|
||||
self:indent(-1)
|
||||
else
|
||||
table.insert(out, line)
|
||||
end
|
||||
end
|
||||
|
||||
local block = table.concat(out, "\n"..self:ichar())
|
||||
if indent_front then
|
||||
block = self:ichar()..block
|
||||
end
|
||||
return block
|
||||
end,
|
||||
|
||||
has_name = function(self, name)
|
||||
for i = #self._scope,1,-1 do
|
||||
if self._scope[i][name] then return true end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
put_name = function(self, name)
|
||||
self._scope:top()[name] = true
|
||||
end,
|
||||
|
||||
get_free_name = function(self, basename)
|
||||
basename = basename or "moon"
|
||||
local i = 0
|
||||
local name
|
||||
repeat
|
||||
name = table.concat({"", basename, i}, "_")
|
||||
i = i + 1
|
||||
until not self:has_name(name)
|
||||
|
||||
return name
|
||||
end,
|
||||
|
||||
ichar = function(self, ...)
|
||||
local depths = {...}
|
||||
if #depths == 0 then
|
||||
return indent_char:rep(self._indent)
|
||||
else
|
||||
local indents = {}
|
||||
for _, v in ipairs(depths) do
|
||||
table.insert(indents, indent_char:rep(self._indent+v))
|
||||
end
|
||||
return unpack(indents)
|
||||
end
|
||||
end,
|
||||
|
||||
chain_item = function(self, node)
|
||||
local t, arg = unpack(node)
|
||||
if t == "call" then
|
||||
return "("..table.concat(self:values(arg), ', ')..")"
|
||||
elseif t == "index" then
|
||||
return "["..self:value(arg).."]"
|
||||
elseif t == "dot" then
|
||||
return "."..arg
|
||||
elseif t == "colon" then
|
||||
return ":"..arg..self:chain_item(node[3])
|
||||
else
|
||||
error("Unknown chain action: "..t)
|
||||
end
|
||||
end,
|
||||
|
||||
chain = function(self, node)
|
||||
local callee = node[2]
|
||||
local actions = {}
|
||||
|
||||
for i = 3,#node do
|
||||
table.insert(actions, self:chain_item(node[i]))
|
||||
end
|
||||
|
||||
-- self function calls operate on self
|
||||
if ntype(callee) == "self" and node[3] and ntype(node[3]) == "call" then
|
||||
callee[1] = "self_colon"
|
||||
end
|
||||
|
||||
local callee_value = self:value(callee)
|
||||
if ntype(callee) == "exp" then
|
||||
callee_value = "("..callee_value..")"
|
||||
end
|
||||
|
||||
return callee_value..table.concat(actions)
|
||||
end,
|
||||
|
||||
import = function(self, node)
|
||||
local _, names, source = unpack(node)
|
||||
|
||||
local to_bind = {}
|
||||
local final_names = {}
|
||||
for _, name in ipairs(names) do
|
||||
if ntype(name) == ":" then
|
||||
name = self:value(name[2])
|
||||
to_bind[name] = true
|
||||
else
|
||||
name = self:value(name)
|
||||
end
|
||||
|
||||
table.insert(final_names, name)
|
||||
self:put_name(name)
|
||||
end
|
||||
|
||||
local function get_values(from)
|
||||
local values = {}
|
||||
for _, name in ipairs(final_names) do
|
||||
local v = to_bind[name] and
|
||||
moonlib.bind(from, name) or from.."."..name
|
||||
table.insert(values, v)
|
||||
end
|
||||
return values
|
||||
end
|
||||
|
||||
-- importing from constant expression
|
||||
if type(source) == "string" then
|
||||
local values = get_values(source)
|
||||
return table.concat({"local", table.concat(final_names, ", "),
|
||||
"=", table.concat(values, ", ")}, " ")
|
||||
end
|
||||
|
||||
local tmp_name = self:get_free_name("table")
|
||||
|
||||
self:push()
|
||||
self:put_name(tmp_name)
|
||||
inner = { "local "..tmp_name.." = "..self:value(source) }
|
||||
|
||||
for i, value in ipairs(get_values(tmp_name)) do
|
||||
table.insert(inner, final_names[i].." = "..value)
|
||||
end
|
||||
self:pop()
|
||||
|
||||
return self:pretty{
|
||||
"local "..table.concat(final_names, ", "),
|
||||
"do", inner, "end"
|
||||
}
|
||||
end,
|
||||
|
||||
fndef = function(self, node)
|
||||
local _, args, arrow, block = unpack(node)
|
||||
self:push()
|
||||
|
||||
for _, arg_name in ipairs(args) do
|
||||
self:put_name(arg_name)
|
||||
end
|
||||
|
||||
if arrow == "fat" then table.insert(args, 1, "self") end
|
||||
args = table.concat(args, ",")
|
||||
|
||||
local out
|
||||
if #block == 0 then
|
||||
out = ("function(%s) end"):format(args)
|
||||
else
|
||||
local inner = self:block(block, true)
|
||||
if #inner == 1 and is_small(inner[1]) then
|
||||
out = ("function(%s) %s end"):format(args, inner[1])
|
||||
else
|
||||
out = self:pretty{
|
||||
("function(%s)"):format(args),
|
||||
inner,
|
||||
"end"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
self:pop()
|
||||
return out
|
||||
end,
|
||||
|
||||
-- compile if
|
||||
["if"] = function(self, node, return_value)
|
||||
local cond, block = node[2], node[3]
|
||||
|
||||
local out = {
|
||||
("if %s then"):format(self:value(cond)),
|
||||
self:block(block, return_value)
|
||||
}
|
||||
|
||||
for i = 4,#node do
|
||||
local clause = node[i]
|
||||
local block
|
||||
if clause[1] == "else" then
|
||||
table.insert(out, "else")
|
||||
block = clause[2]
|
||||
elseif clause[1] == "elseif" then
|
||||
table.insert(out, "elseif "..self:value(clause[2]).." then")
|
||||
block = clause[3]
|
||||
else
|
||||
error("Unknown if clause: "..clause[1])
|
||||
end
|
||||
table.insert(out, self:block(block, return_value))
|
||||
end
|
||||
|
||||
table.insert(out, "end")
|
||||
|
||||
return self:pretty(out)
|
||||
end,
|
||||
|
||||
['while'] = function(self, node)
|
||||
local _, cond, block = unpack(node)
|
||||
|
||||
return self:pretty{
|
||||
("while %s do"):format(self:value(cond)),
|
||||
self:block(block),
|
||||
"end"
|
||||
}
|
||||
end,
|
||||
|
||||
name_list = function(self, node)
|
||||
return table.concat(self:values(node), ", ")
|
||||
end,
|
||||
|
||||
-- need to get tmp name instead of using tmp
|
||||
comprehension = function(self, node, return_value)
|
||||
local _, exp, clauses = unpack(node)
|
||||
|
||||
local action = return_value
|
||||
and { ("table.insert(tmp, %s)"):format(self:value(exp)) }
|
||||
or { self:stm(exp) }
|
||||
|
||||
self:push()
|
||||
for i = #clauses,1,-1 do
|
||||
local c = clauses[i]
|
||||
|
||||
if "for" == c[1] then
|
||||
local _, names, iter = unpack(c)
|
||||
if ntype(iter) == "unpack" then
|
||||
iter = iter[2]
|
||||
local items_tmp, index_tmp = self:get_free_name("items"), self:get_free_name("index")
|
||||
|
||||
self:put_name(items_tmp)
|
||||
self:put_name(index_tmp)
|
||||
|
||||
action = {
|
||||
("local %s = %s"):format(items_tmp, self:value(iter)),
|
||||
("for %s=1,#%s do"):format(index_tmp, items_tmp),
|
||||
{("local %s = %s[%s]"):format(self:name_list(names), items_tmp, index_tmp)},
|
||||
action,
|
||||
"end"
|
||||
}
|
||||
else
|
||||
action = {
|
||||
("for %s in %s do"):format(self:name_list(names), self:value(iter)),
|
||||
action,
|
||||
"end"
|
||||
}
|
||||
end
|
||||
elseif "when" == c[1] then
|
||||
local _, when = unpack(c)
|
||||
action = {
|
||||
("if %s then"):format(self:value(when)),
|
||||
action,
|
||||
"end"
|
||||
}
|
||||
else
|
||||
error("Unknown clause type :"..tostring(c[1]))
|
||||
end
|
||||
end
|
||||
self:pop()
|
||||
|
||||
if return_value then
|
||||
return self:pretty{
|
||||
"(function()",
|
||||
{ "local tmp = {}", },
|
||||
action,
|
||||
{ "return tmp" },
|
||||
"end)()"
|
||||
}
|
||||
else
|
||||
return self:pretty(action)
|
||||
end
|
||||
end,
|
||||
|
||||
-- returns list of compiled statements
|
||||
block = function(self, node, return_value, inc)
|
||||
inc = inc or 1
|
||||
|
||||
self:push()
|
||||
self:indent(inc)
|
||||
|
||||
local lines = {}
|
||||
local len = #node
|
||||
for i=1,len do
|
||||
local ln = node[i]
|
||||
local value = self:stm(ln, i == len and return_value)
|
||||
if type(value) == "table" then
|
||||
for _, v in ipairs(value) do
|
||||
table.insert(lines, v)
|
||||
end
|
||||
else
|
||||
table.insert(lines, value)
|
||||
end
|
||||
end
|
||||
|
||||
-- add semicolons where they might be needed
|
||||
for i, left, k, right in itwos(lines) do
|
||||
if left:sub(-1) == ")" and right:sub(1,1) == "(" then
|
||||
lines[i] = lines[i]..";"
|
||||
end
|
||||
end
|
||||
|
||||
self:indent(-inc)
|
||||
self:pop()
|
||||
|
||||
return lines
|
||||
end,
|
||||
|
||||
table = function(self, node)
|
||||
local _, items = unpack(node)
|
||||
|
||||
self:indent(1)
|
||||
local len = #items
|
||||
local item_values = {}
|
||||
for i = 1,len do
|
||||
local item = items[i]
|
||||
local item_value
|
||||
if #item == 1 then
|
||||
item_value = self:value(item[1])
|
||||
else
|
||||
local key = self:value(item[1])
|
||||
if type(item[1]) ~= "string" then
|
||||
key = ("[%s]"):format(key)
|
||||
end
|
||||
|
||||
item_value = key.." = "..self:value(item[2])
|
||||
end
|
||||
|
||||
if i ~= len then
|
||||
item_value = item_value..","
|
||||
end
|
||||
|
||||
table.insert(item_values, item_value)
|
||||
end
|
||||
self:indent(-1)
|
||||
|
||||
if #item_values > 3 then
|
||||
return self:pretty{ "{", item_values, "}" }
|
||||
end
|
||||
|
||||
return "{ "..table.concat(item_values, " ").." }"
|
||||
end,
|
||||
|
||||
assign = function(self, node)
|
||||
local _, names, values = unpack(node)
|
||||
|
||||
-- declare undeclared names
|
||||
local undeclared_names = {}
|
||||
for _, name in ipairs(names) do
|
||||
if type(name) == "string" and not self:has_name(name) then
|
||||
table.insert(undeclared_names, name)
|
||||
self:put_name(name)
|
||||
end
|
||||
end
|
||||
|
||||
local compact = not block_statements[ntype(values)] and #undeclared_names == #names
|
||||
-- if there is an fndef in there, don't do compact
|
||||
for _, v in ipairs(values) do
|
||||
if ntype(v) == "fndef" then
|
||||
compact = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
local num_undeclared = #undeclared_names
|
||||
if num_undeclared > 0 and not compact then
|
||||
table.insert(lines, "local "..table.concat(undeclared_names, ", "))
|
||||
end
|
||||
|
||||
if block_statements[ntype(values)] then
|
||||
table.insert(lines, self:stm(values, self:name_list(names)))
|
||||
else
|
||||
local ln = self:name_list(names).." = "..table.concat(self:values(values), ", ")
|
||||
|
||||
if compact then
|
||||
ln = "local "..ln
|
||||
end
|
||||
|
||||
table.insert(lines, ln)
|
||||
end
|
||||
|
||||
return self:pretty(lines)
|
||||
end,
|
||||
|
||||
exp = function(self, node)
|
||||
local values = {}
|
||||
for i = 2, #node do
|
||||
if i % 2 == 1 and node[i] == "!=" then
|
||||
node[i] = "~="
|
||||
end
|
||||
table.insert(values, self:value(node[i]))
|
||||
end
|
||||
return table.concat(values, " ")
|
||||
end,
|
||||
|
||||
parens = function(self, node)
|
||||
local _, value = unpack(node)
|
||||
return '('..self:value(value)..')'
|
||||
end,
|
||||
|
||||
string = function(self, node)
|
||||
local _, delim, inner, delim_end = unpack(node)
|
||||
return delim..inner..(delim_end or delim)
|
||||
end,
|
||||
|
||||
explist = function(self, node)
|
||||
local values = {}
|
||||
for i=2,#node do
|
||||
table.insert(values, self:value(node[i]))
|
||||
end
|
||||
return table.concat(values, ", ")
|
||||
end,
|
||||
|
||||
value = function(self, node, return_value, ...)
|
||||
if return_value == nil then return_value = true end
|
||||
|
||||
if type(node) == "table" then
|
||||
local fn = self[node[1]]
|
||||
if not fn then
|
||||
error("Unknown op: "..tostring(node[1]))
|
||||
end
|
||||
return fn(self, node, return_value, ...)
|
||||
end
|
||||
|
||||
return node
|
||||
end,
|
||||
|
||||
-- has no return value, meant to be on line of it's own
|
||||
stm = function(self, node, return_value)
|
||||
local value = self:value(node, return_value)
|
||||
|
||||
local is_value = must_return[ntype(node)]
|
||||
local ret_chain = ntype(node) == "chain" and node[2] ~= "return"
|
||||
|
||||
if return_value and (is_value or ret_chain) then
|
||||
local return_to = "return"
|
||||
if type(return_value) == "string" then
|
||||
return_to = return_value.." ="
|
||||
end
|
||||
|
||||
return return_to.." "..value
|
||||
elseif is_value then
|
||||
return self:value({"assign", {"_"}, {value}}, false)
|
||||
end
|
||||
|
||||
return value
|
||||
end,
|
||||
|
||||
minus = function(self, node)
|
||||
local _, value = unpack(node)
|
||||
return "-"..self:value(value)
|
||||
end,
|
||||
|
||||
length = function(self, node)
|
||||
local _, value = unpack(node)
|
||||
return "#"..self:value(value)
|
||||
end,
|
||||
|
||||
["not"] = function(self, node)
|
||||
local _, value = unpack(node)
|
||||
return "not "..self:value(value)
|
||||
end,
|
||||
|
||||
self = function(self, node)
|
||||
local _, val = unpack(node)
|
||||
return "self."..self:value(val)
|
||||
end,
|
||||
|
||||
self_colon = function(self, node)
|
||||
local _, val = unpack(node)
|
||||
return "self:"..self:value(val)
|
||||
end,
|
||||
|
||||
-- a list of values
|
||||
values = function(self, items, start)
|
||||
start = start or 1
|
||||
local compiled = {}
|
||||
for i = start,#items do
|
||||
table.insert(compiled, self:value(items[i]))
|
||||
end
|
||||
return compiled
|
||||
end
|
||||
}
|
||||
|
||||
function build_compiler()
|
||||
return setmetatable({
|
||||
_indent = 0,
|
||||
_scope = Stack({}),
|
||||
}, { __index = compiler_index })
|
||||
end
|
||||
|
||||
function tree(tree)
|
||||
local compiler = build_compiler()
|
||||
return compiler:pretty(compiler:block(tree, false, 0))
|
||||
end
|
||||
|
||||
|
175
moonscript/compile/value.lua
Normal file
175
moonscript/compile/value.lua
Normal file
@ -0,0 +1,175 @@
|
||||
module("moonscript.compile", package.seeall)
|
||||
local util = require("moonscript.util")
|
||||
local data = require("moonscript.data")
|
||||
require("moonscript.compile.format")
|
||||
local ntype = data.ntype
|
||||
local concat, insert = table.concat, table.insert
|
||||
value_compile = {
|
||||
exp = function(self, node)
|
||||
local _comp
|
||||
_comp = function(i, value)
|
||||
if i % 2 == 1 and value == "!=" then
|
||||
value = "~="
|
||||
end
|
||||
return self:value(value)
|
||||
end
|
||||
return concat((function()
|
||||
local _moon_0 = {}
|
||||
for i, v in ipairs(node) do
|
||||
if i > 1 then
|
||||
table.insert(_moon_0, _comp(i, v))
|
||||
end
|
||||
end
|
||||
return _moon_0
|
||||
end)(), " ")
|
||||
end,
|
||||
update = function(self, node)
|
||||
local _, name = unpack(node)
|
||||
self:stm(node)
|
||||
return self:name(name)
|
||||
end,
|
||||
explist = function(self, node) return concat((function()
|
||||
local _moon_0 = {}
|
||||
local _item_0 = node
|
||||
for _index_0=2,#_item_0 do
|
||||
local v = _item_0[_index_0]
|
||||
table.insert(_moon_0, self:value(v))
|
||||
end
|
||||
return _moon_0
|
||||
end)(), ", ") end,
|
||||
parens = function(self, node) return "(" .. (self:value(node[2])) .. ")" end,
|
||||
string = function(self, node)
|
||||
local _, delim, inner, delim_end = unpack(node)
|
||||
return delim .. inner .. (delim_end or delim)
|
||||
end,
|
||||
["if"] = function(self, node)
|
||||
local func = self:block()
|
||||
func:stm(node, returner)
|
||||
return self:format("(function()", func:render(), "end)()")
|
||||
end,
|
||||
comprehension = function(self, node)
|
||||
local exp = node[2]
|
||||
local func = self:block()
|
||||
local tmp_name = func:free_name()
|
||||
func:add_line("local", tmp_name, "= {}")
|
||||
local action = func:block()
|
||||
action:add_line(("table.insert(%s, %s)"):format(tmp_name, func:value(exp)))
|
||||
func:stm(node, action)
|
||||
func:add_line("return", tmp_name)
|
||||
return self:format("(function()", func:render(), "end)()")
|
||||
end,
|
||||
chain = function(self, node)
|
||||
local callee = node[2]
|
||||
if callee == -1 then
|
||||
callee = self:get("scope_var")
|
||||
if not callee then
|
||||
error("Short-dot syntax must be called within a with block")
|
||||
end
|
||||
end
|
||||
local sup = self:get("super")
|
||||
if callee == "super" and sup then
|
||||
return(self:value(sup(self, node)))
|
||||
end
|
||||
local chain_item
|
||||
chain_item = function(node)
|
||||
local t, arg = unpack(node)
|
||||
if t == "call" then
|
||||
return "(" .. (self:values(arg)) .. ")"
|
||||
elseif t == "index" then
|
||||
return "[" .. (self:value(arg)) .. "]"
|
||||
elseif t == "dot" then
|
||||
return "." .. arg
|
||||
elseif t == "colon" then
|
||||
return ":" .. arg .. (chain_item(node[3]))
|
||||
else
|
||||
return error("Unknown chain action: " .. t)
|
||||
end
|
||||
end
|
||||
local actions = (function()
|
||||
local _moon_0 = {}
|
||||
local _item_0 = node
|
||||
for _index_0=3,#_item_0 do
|
||||
local act = _item_0[_index_0]
|
||||
table.insert(_moon_0, chain_item(act))
|
||||
end
|
||||
return _moon_0
|
||||
end)()
|
||||
if ntype(callee) == "self" and node[3] and ntype(node[3]) == "call" then
|
||||
callee[1] = "self_colon"
|
||||
end
|
||||
local callee_value = self:name(callee)
|
||||
if ntype(callee) == "exp" then
|
||||
callee_value = "(" .. callee_value .. ")"
|
||||
end
|
||||
return self:name(callee) .. concat(actions)
|
||||
end,
|
||||
fndef = function(self, node)
|
||||
local _, args, arrow, block = unpack(node)
|
||||
if arrow == "fat" then
|
||||
insert(args, 1, "self")
|
||||
end
|
||||
local b = self:block()
|
||||
local _item_0 = args
|
||||
for _index_0=1,#_item_0 do
|
||||
local name = _item_0[_index_0]
|
||||
b:put_name(name)
|
||||
end
|
||||
b:ret_stms(block)
|
||||
local decl = "function(" .. (concat(args, ", ")) .. ")"
|
||||
if #b._lines == 0 then
|
||||
return decl .. " end"
|
||||
elseif #b._lines == 1 then
|
||||
return concat({ decl, b._lines[1], "end" }, " ")
|
||||
else
|
||||
return self:format(decl, b._lines, "end")
|
||||
end
|
||||
end,
|
||||
table = function(self, node)
|
||||
local _, items = unpack(node)
|
||||
local inner = self:block()
|
||||
local _comp
|
||||
_comp = function(i, tuple)
|
||||
local out
|
||||
if #tuple == 2 then
|
||||
local key, value = unpack(tuple)
|
||||
if type(key) == "string" and data.lua_keywords[key] then
|
||||
key = { "string", '"', key }
|
||||
end
|
||||
local key_val = self:value(key)
|
||||
if type(key) ~= "string" then
|
||||
key = ("[%s]"):format(key_val)
|
||||
else
|
||||
key = key_val
|
||||
end
|
||||
inner:set("current_block", key_val)
|
||||
value = inner:value(value)
|
||||
inner:set("current_block", nil)
|
||||
out = ("%s = %s"):format(key, value)
|
||||
else
|
||||
out = inner:value(tuple[1])
|
||||
end
|
||||
if i ~= #items then
|
||||
return out .. ","
|
||||
else
|
||||
return out
|
||||
end
|
||||
end
|
||||
local values = (function()
|
||||
local _moon_0 = {}
|
||||
for i, v in ipairs(items) do
|
||||
table.insert(_moon_0, _comp(i, v))
|
||||
end
|
||||
return _moon_0
|
||||
end)()
|
||||
if #values > 3 then
|
||||
return self:format("{", values, "}")
|
||||
else
|
||||
return "{ " .. (concat(values, " ")) .. " }"
|
||||
end
|
||||
end,
|
||||
minus = function(self, node) return "-" .. self:value(node[2]) end,
|
||||
length = function(self, node) return "#" .. self:value(node[2]) end,
|
||||
["not"] = function(self, node) return "not " .. self:value(node[2]) end,
|
||||
self = function(self, node) return "self." .. self:value(node[2]) end,
|
||||
self_colon = function(self, node) return "self:" .. self:value(node[2]) end
|
||||
}
|
158
moonscript/compile/value.moon
Normal file
158
moonscript/compile/value.moon
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
module "moonscript.compile", package.seeall
|
||||
|
||||
util = require "moonscript.util"
|
||||
data = require "moonscript.data"
|
||||
|
||||
require "moonscript.compile.format"
|
||||
|
||||
import ntype from data
|
||||
import concat, insert from table
|
||||
|
||||
export value_compile
|
||||
|
||||
value_compile =
|
||||
exp: (node) =>
|
||||
_comp = (i, value) ->
|
||||
if i % 2 == 1 and value == "!="
|
||||
value = "~="
|
||||
@value value
|
||||
|
||||
-- ugly
|
||||
concat [_comp i,v for i,v in ipairs node when i > 1], " "
|
||||
|
||||
update: (node) =>
|
||||
_, name = unpack node
|
||||
@stm node
|
||||
@name name
|
||||
|
||||
explist: (node) =>
|
||||
concat [@value v for v in *node[2:]], ", "
|
||||
|
||||
parens: (node) =>
|
||||
"("..(@value node[2])..")"
|
||||
|
||||
string: (node) =>
|
||||
_, delim, inner, delim_end = unpack node
|
||||
delim..inner..(delim_end or delim)
|
||||
|
||||
if: (node) =>
|
||||
func = @block!
|
||||
func\stm node, returner
|
||||
@format "(function()", func\render!, "end)()"
|
||||
|
||||
comprehension: (node) =>
|
||||
exp = node[2]
|
||||
func = @block!
|
||||
tmp_name = func\free_name!
|
||||
|
||||
func\add_line "local", tmp_name, "= {}"
|
||||
|
||||
action = func\block!
|
||||
action\add_line ("table.insert(%s, %s)")\format(tmp_name, func\value exp)
|
||||
func\stm node, action
|
||||
|
||||
func\add_line "return", tmp_name
|
||||
|
||||
@format "(function()", func\render!, "end)()"
|
||||
|
||||
chain: (node) =>
|
||||
callee = node[2]
|
||||
|
||||
if callee == -1
|
||||
callee = @get"scope_var"
|
||||
if not callee then error"Short-dot syntax must be called within a with block"
|
||||
|
||||
sup = @get "super"
|
||||
if callee == "super" and sup
|
||||
return @value sup self, node
|
||||
|
||||
chain_item = (node) ->
|
||||
t, arg = unpack node
|
||||
if t == "call"
|
||||
"("..(@values arg)..")"
|
||||
elseif t == "index"
|
||||
"["..(@value arg).."]"
|
||||
elseif t == "dot"
|
||||
"."..arg
|
||||
elseif t == "colon"
|
||||
":"..arg..(chain_item node[3])
|
||||
else
|
||||
error "Unknown chain action: "..t
|
||||
|
||||
actions = [chain_item act for act in *node[3:]]
|
||||
|
||||
if ntype(callee) == "self" and node[3] and ntype(node[3]) == "call"
|
||||
callee[1] = "self_colon"
|
||||
|
||||
callee_value = @name callee
|
||||
callee_value = "("..callee_value..")" if ntype(callee) == "exp"
|
||||
|
||||
return @name(callee)..concat(actions)
|
||||
|
||||
fndef: (node) =>
|
||||
_, args, arrow, block = unpack node
|
||||
|
||||
if arrow == "fat"
|
||||
insert args, 1, "self"
|
||||
|
||||
b = @block!
|
||||
b\put_name name for name in *args
|
||||
b\ret_stms block
|
||||
|
||||
decl = "function("..(concat args, ", ")..")"
|
||||
if #b._lines == 0
|
||||
decl.." end"
|
||||
elseif #b._lines == 1
|
||||
concat {decl, b._lines[1], "end"}, " "
|
||||
else
|
||||
@format decl, b._lines, "end"
|
||||
|
||||
table: (node) =>
|
||||
_, items = unpack node
|
||||
|
||||
inner = @block! -- handle indent
|
||||
_comp = (i, tuple) ->
|
||||
out = if #tuple == 2
|
||||
key, value = unpack tuple
|
||||
|
||||
if type(key) == "string" and data.lua_keywords[key]
|
||||
key = {"string", '"', key}
|
||||
|
||||
key_val = @value key
|
||||
key = if type(key) != "string"
|
||||
("[%s]")\format key_val
|
||||
else
|
||||
key_val
|
||||
|
||||
inner\set "current_block", key_val
|
||||
value = inner\value value
|
||||
inner\set "current_block", nil
|
||||
|
||||
("%s = %s")\format key, value
|
||||
else
|
||||
inner\value tuple[1]
|
||||
|
||||
out.."," if i != #items else out
|
||||
|
||||
values = [_comp i,v for i,v in ipairs items]
|
||||
|
||||
if #values > 3
|
||||
@format "{", values, "}"
|
||||
else
|
||||
"{ "..(concat values, " ").." }"
|
||||
|
||||
minus: (node) =>
|
||||
"-"..@value node[2]
|
||||
|
||||
length: (node) =>
|
||||
"#"..@value node[2]
|
||||
|
||||
not: (node) =>
|
||||
"not "..@value node[2]
|
||||
|
||||
self: (node) =>
|
||||
"self."..@value node[2]
|
||||
|
||||
self_colon: (node) =>
|
||||
"self:"..@value node[2]
|
@ -4,178 +4,9 @@ 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
|
||||
require("moonscript.compile.value")
|
||||
local ntype = data.ntype
|
||||
local concat, insert = table.concat, table.insert
|
||||
local value_compile = {
|
||||
exp = function(self, node)
|
||||
local _comp
|
||||
_comp = function(i, value)
|
||||
if i % 2 == 1 and value == "!=" then
|
||||
value = "~="
|
||||
end
|
||||
return self:value(value)
|
||||
end
|
||||
return concat((function()
|
||||
local _moon_0 = {}
|
||||
for i, v in ipairs(node) do
|
||||
if i > 1 then
|
||||
table.insert(_moon_0, _comp(i, v))
|
||||
end
|
||||
end
|
||||
return _moon_0
|
||||
end)(), " ")
|
||||
end,
|
||||
update = function(self, node)
|
||||
local _, name = unpack(node)
|
||||
self:stm(node)
|
||||
return self:name(name)
|
||||
end,
|
||||
explist = function(self, node) return concat((function()
|
||||
local _moon_0 = {}
|
||||
local _item_0 = node
|
||||
for _index_0=2,#_item_0 do
|
||||
local v = _item_0[_index_0]
|
||||
table.insert(_moon_0, self:value(v))
|
||||
end
|
||||
return _moon_0
|
||||
end)(), ", ") end,
|
||||
parens = function(self, node) return "(" .. (self:value(node[2])) .. ")" end,
|
||||
string = function(self, node)
|
||||
local _, delim, inner, delim_end = unpack(node)
|
||||
return delim .. inner .. (delim_end or delim)
|
||||
end,
|
||||
["if"] = function(self, node)
|
||||
local func = self:block()
|
||||
func:stm(node, returner)
|
||||
return self:format("(function()", func:render(), "end)()")
|
||||
end,
|
||||
comprehension = function(self, node)
|
||||
local exp = node[2]
|
||||
local func = self:block()
|
||||
local tmp_name = func:free_name()
|
||||
func:add_line("local", tmp_name, "= {}")
|
||||
local action = func:block()
|
||||
action:add_line(("table.insert(%s, %s)"):format(tmp_name, func:value(exp)))
|
||||
func:stm(node, action)
|
||||
func:add_line("return", tmp_name)
|
||||
return self:format("(function()", func:render(), "end)()")
|
||||
end,
|
||||
chain = function(self, node)
|
||||
local callee = node[2]
|
||||
if callee == -1 then
|
||||
callee = self:get("scope_var")
|
||||
if not callee then
|
||||
error("Short-dot syntax must be called within a with block")
|
||||
end
|
||||
end
|
||||
local sup = self:get("super")
|
||||
if callee == "super" and sup then
|
||||
return(self:value(sup(self, node)))
|
||||
end
|
||||
local chain_item
|
||||
chain_item = function(node)
|
||||
local t, arg = unpack(node)
|
||||
if t == "call" then
|
||||
return "(" .. (self:values(arg)) .. ")"
|
||||
elseif t == "index" then
|
||||
return "[" .. (self:value(arg)) .. "]"
|
||||
elseif t == "dot" then
|
||||
return "." .. arg
|
||||
elseif t == "colon" then
|
||||
return ":" .. arg .. (chain_item(node[3]))
|
||||
else
|
||||
return error("Unknown chain action: " .. t)
|
||||
end
|
||||
end
|
||||
local actions = (function()
|
||||
local _moon_0 = {}
|
||||
local _item_0 = node
|
||||
for _index_0=3,#_item_0 do
|
||||
local act = _item_0[_index_0]
|
||||
table.insert(_moon_0, chain_item(act))
|
||||
end
|
||||
return _moon_0
|
||||
end)()
|
||||
if ntype(callee) == "self" and node[3] and ntype(node[3]) == "call" then
|
||||
callee[1] = "self_colon"
|
||||
end
|
||||
local callee_value = self:name(callee)
|
||||
if ntype(callee) == "exp" then
|
||||
callee_value = "(" .. callee_value .. ")"
|
||||
end
|
||||
return self:name(callee) .. concat(actions)
|
||||
end,
|
||||
fndef = function(self, node)
|
||||
local _, args, arrow, block = unpack(node)
|
||||
if arrow == "fat" then
|
||||
insert(args, 1, "self")
|
||||
end
|
||||
local b = self:block()
|
||||
local _item_0 = args
|
||||
for _index_0=1,#_item_0 do
|
||||
local name = _item_0[_index_0]
|
||||
b:put_name(name)
|
||||
end
|
||||
b:ret_stms(block)
|
||||
local decl = "function(" .. (concat(args, ", ")) .. ")"
|
||||
if #b._lines == 0 then
|
||||
return decl .. " end"
|
||||
elseif #b._lines == 1 then
|
||||
return concat({ decl, b._lines[1], "end" }, " ")
|
||||
else
|
||||
return self:format(decl, b._lines, "end")
|
||||
end
|
||||
end,
|
||||
table = function(self, node)
|
||||
local _, items = unpack(node)
|
||||
local inner = self:block()
|
||||
local _comp
|
||||
_comp = function(i, tuple)
|
||||
local out
|
||||
if #tuple == 2 then
|
||||
local key, value = unpack(tuple)
|
||||
if type(key) == "string" and data.lua_keywords[key] then
|
||||
key = { "string", '"', key }
|
||||
end
|
||||
local key_val = self:value(key)
|
||||
if type(key) ~= "string" then
|
||||
key = ("[%s]"):format(key_val)
|
||||
else
|
||||
key = key_val
|
||||
end
|
||||
inner:set("current_block", key_val)
|
||||
value = inner:value(value)
|
||||
inner:set("current_block", nil)
|
||||
out = ("%s = %s"):format(key, value)
|
||||
else
|
||||
out = inner:value(tuple[1])
|
||||
end
|
||||
if i ~= #items then
|
||||
return out .. ","
|
||||
else
|
||||
return out
|
||||
end
|
||||
end
|
||||
local values = (function()
|
||||
local _moon_0 = {}
|
||||
for i, v in ipairs(items) do
|
||||
table.insert(_moon_0, _comp(i, v))
|
||||
end
|
||||
return _moon_0
|
||||
end)()
|
||||
if #values > 3 then
|
||||
return self:format("{", values, "}")
|
||||
else
|
||||
return "{ " .. (concat(values, " ")) .. " }"
|
||||
end
|
||||
end,
|
||||
minus = function(self, node) return "-" .. self:value(node[2]) end,
|
||||
length = function(self, node) return "#" .. self:value(node[2]) end,
|
||||
["not"] = function(self, node) return "not " .. self:value(node[2]) end,
|
||||
self = function(self, node) return "self." .. self:value(node[2]) end,
|
||||
self_colon = function(self, node) return "self:" .. self:value(node[2]) end
|
||||
}
|
||||
local Block
|
||||
Block = (function(_parent_0)
|
||||
local _base_0 = {
|
||||
@ -352,11 +183,6 @@ Block = (function(_parent_0)
|
||||
return self
|
||||
end })
|
||||
end)()
|
||||
local build_compiler
|
||||
build_compiler = function()
|
||||
Block(nil)
|
||||
return setmetatable({ }, { __index = compiler_index })
|
||||
end
|
||||
tree = function(tree)
|
||||
local scope = Block()
|
||||
local _item_0 = tree
|
||||
|
@ -6,159 +6,13 @@ dump = require "moonscript.dump"
|
||||
|
||||
require "moonscript.compile.format"
|
||||
require "moonscript.compile.line"
|
||||
require "moonscript.compile.value"
|
||||
|
||||
import map, bind, itwos, every, reversed from util
|
||||
import Stack, Set, ntype from data
|
||||
import ntype from data
|
||||
import concat, insert from table
|
||||
|
||||
export tree
|
||||
|
||||
value_compile =
|
||||
exp: (node) =>
|
||||
_comp = (i, value) ->
|
||||
if i % 2 == 1 and value == "!="
|
||||
value = "~="
|
||||
@value value
|
||||
|
||||
-- ugly
|
||||
concat [_comp i,v for i,v in ipairs node when i > 1], " "
|
||||
|
||||
update: (node) =>
|
||||
_, name = unpack node
|
||||
@stm node
|
||||
@name name
|
||||
|
||||
explist: (node) =>
|
||||
concat [@value v for v in *node[2:]], ", "
|
||||
|
||||
parens: (node) =>
|
||||
"("..(@value node[2])..")"
|
||||
|
||||
string: (node) =>
|
||||
_, delim, inner, delim_end = unpack node
|
||||
delim..inner..(delim_end or delim)
|
||||
|
||||
if: (node) =>
|
||||
func = @block!
|
||||
func\stm node, returner
|
||||
@format "(function()", func\render!, "end)()"
|
||||
|
||||
comprehension: (node) =>
|
||||
exp = node[2]
|
||||
func = @block!
|
||||
tmp_name = func\free_name!
|
||||
|
||||
func\add_line "local", tmp_name, "= {}"
|
||||
|
||||
action = func\block!
|
||||
action\add_line ("table.insert(%s, %s)")\format(tmp_name, func\value exp)
|
||||
func\stm node, action
|
||||
|
||||
func\add_line "return", tmp_name
|
||||
|
||||
@format "(function()", func\render!, "end)()"
|
||||
|
||||
chain: (node) =>
|
||||
callee = node[2]
|
||||
|
||||
if callee == -1
|
||||
callee = @get"scope_var"
|
||||
if not callee then error"Short-dot syntax must be called within a with block"
|
||||
|
||||
sup = @get "super"
|
||||
if callee == "super" and sup
|
||||
return @value sup self, node
|
||||
|
||||
chain_item = (node) ->
|
||||
t, arg = unpack node
|
||||
if t == "call"
|
||||
"("..(@values arg)..")"
|
||||
elseif t == "index"
|
||||
"["..(@value arg).."]"
|
||||
elseif t == "dot"
|
||||
"."..arg
|
||||
elseif t == "colon"
|
||||
":"..arg..(chain_item node[3])
|
||||
else
|
||||
error "Unknown chain action: "..t
|
||||
|
||||
actions = [chain_item act for act in *node[3:]]
|
||||
|
||||
if ntype(callee) == "self" and node[3] and ntype(node[3]) == "call"
|
||||
callee[1] = "self_colon"
|
||||
|
||||
callee_value = @name callee
|
||||
callee_value = "("..callee_value..")" if ntype(callee) == "exp"
|
||||
|
||||
return @name(callee)..concat(actions)
|
||||
|
||||
fndef: (node) =>
|
||||
_, args, arrow, block = unpack node
|
||||
|
||||
if arrow == "fat"
|
||||
insert args, 1, "self"
|
||||
|
||||
b = @block!
|
||||
b\put_name name for name in *args
|
||||
b\ret_stms block
|
||||
|
||||
decl = "function("..(concat args, ", ")..")"
|
||||
if #b._lines == 0
|
||||
decl.." end"
|
||||
elseif #b._lines == 1
|
||||
concat {decl, b._lines[1], "end"}, " "
|
||||
else
|
||||
@format decl, b._lines, "end"
|
||||
|
||||
table: (node) =>
|
||||
_, items = unpack node
|
||||
|
||||
inner = @block! -- handle indent
|
||||
_comp = (i, tuple) ->
|
||||
out = if #tuple == 2
|
||||
key, value = unpack tuple
|
||||
|
||||
if type(key) == "string" and data.lua_keywords[key]
|
||||
key = {"string", '"', key}
|
||||
|
||||
key_val = @value key
|
||||
key = if type(key) != "string"
|
||||
("[%s]")\format key_val
|
||||
else
|
||||
key_val
|
||||
|
||||
inner\set "current_block", key_val
|
||||
value = inner\value value
|
||||
inner\set "current_block", nil
|
||||
|
||||
("%s = %s")\format key, value
|
||||
else
|
||||
inner\value tuple[1]
|
||||
|
||||
out.."," if i != #items else out
|
||||
|
||||
values = [_comp i,v for i,v in ipairs items]
|
||||
|
||||
if #values > 3
|
||||
@format "{", values, "}"
|
||||
else
|
||||
"{ "..(concat values, " ").." }"
|
||||
|
||||
minus: (node) =>
|
||||
"-"..@value node[2]
|
||||
|
||||
length: (node) =>
|
||||
"#"..@value node[2]
|
||||
|
||||
not: (node) =>
|
||||
"not "..@value node[2]
|
||||
|
||||
self: (node) =>
|
||||
"self."..@value node[2]
|
||||
|
||||
self_colon: (node) =>
|
||||
"self:"..@value node[2]
|
||||
|
||||
class Block
|
||||
new: (@parent) =>
|
||||
@set_indent @parent and @parent.indent + 1 or 0
|
||||
@ -304,15 +158,9 @@ class Block
|
||||
@stm stm for stm in *stms
|
||||
nil
|
||||
|
||||
build_compiler = ->
|
||||
Block(nil)
|
||||
setmetatable {}, { __index: compiler_index }
|
||||
|
||||
tree = (tree) ->
|
||||
scope = Block!
|
||||
scope\stm line for line in *tree
|
||||
|
||||
-- print util.dump scope._posmap
|
||||
|
||||
scope\render!, scope\line_table!
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user