mirror of
https://github.com/leafo/moonscript.git
synced 2024-10-05 05:34:19 +00:00
split compiler across multiple files
This commit is contained in:
parent
f133f263b4
commit
c6aa90bcbc
70
moonscript/compile/format.lua
Normal file
70
moonscript/compile/format.lua
Normal 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
|
58
moonscript/compile/format.moon
Normal file
58
moonscript/compile/format.moon
Normal 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
320
moonscript/compile/line.lua
Normal 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
|
||||
}
|
258
moonscript/compile/line.moon
Normal file
258
moonscript/compile/line.moon
Normal 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?
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user