mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
assignment and scoping functional
This commit is contained in:
parent
4936446f1c
commit
4d489581ba
@ -2,6 +2,8 @@
|
||||
module("moonscript.compile", package.seeall)
|
||||
require "util"
|
||||
|
||||
local data = require "moonscript.data"
|
||||
|
||||
-- this doesn't work
|
||||
-- setmetatable(_M, {
|
||||
-- __call = setfenv(function(self, ...)
|
||||
@ -10,6 +12,7 @@ require "util"
|
||||
-- })
|
||||
|
||||
local map, bind = util.map, util.bind
|
||||
local Stack = data.Stack
|
||||
|
||||
local indent_char = " "
|
||||
|
||||
@ -20,6 +23,22 @@ end
|
||||
|
||||
local compilers = {
|
||||
_indent = 0,
|
||||
_scope = Stack({}),
|
||||
|
||||
push = function(self) self._scope:push{} end,
|
||||
pop = function(self) self._scope:pop() 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,
|
||||
|
||||
ichar = function(self)
|
||||
return indent_char:rep(self._indent)
|
||||
end,
|
||||
@ -48,14 +67,26 @@ local compilers = {
|
||||
|
||||
fndef = function(self, node)
|
||||
local _, args, block = unpack(node)
|
||||
if #block == 0 then
|
||||
return "function() end"
|
||||
elseif #block == 1 then
|
||||
return ("function(%s) %s end"):format(
|
||||
table.concat(args, ", "), self:value(block[1]))
|
||||
self:push()
|
||||
|
||||
for _, arg_name in ipairs(args) do
|
||||
self:put_name(arg_name)
|
||||
end
|
||||
return ("function(%s)\n%s\n%send"):format(
|
||||
table.concat(args, ", "), self:block(block, 1), self:ichar())
|
||||
|
||||
args = table.concat(args, ",")
|
||||
|
||||
local out
|
||||
if #block == 0 then
|
||||
out = ("function(%s) end"):format(args)
|
||||
elseif #block == 1 then
|
||||
out = ("function(%s) %s end"):format(args, self:value(block[1]))
|
||||
else
|
||||
out = ("function(%s)\n%s\n%send"):format(
|
||||
args, self:block(block, 1), self:ichar())
|
||||
end
|
||||
|
||||
self:pop()
|
||||
return out
|
||||
end,
|
||||
|
||||
["if"] = function(self, node)
|
||||
@ -65,6 +96,7 @@ local compilers = {
|
||||
end,
|
||||
|
||||
block = function(self, node, inc)
|
||||
self:push()
|
||||
if inc then self._indent = self._indent + inc end
|
||||
local lines = {}
|
||||
local i = self:ichar()
|
||||
@ -72,12 +104,47 @@ local compilers = {
|
||||
table.insert(lines, i..self:value(ln))
|
||||
end
|
||||
if inc then self._indent = self._indent - inc end
|
||||
self:pop()
|
||||
return table.concat(lines, "\n")
|
||||
end,
|
||||
|
||||
assign = function(self, node)
|
||||
local _, names, values = unpack(node)
|
||||
return "local "..table.concat(names, ", ").." = "..table.concat(self:values(values), ", ")
|
||||
local assigns, current = {}, nil
|
||||
|
||||
local function append(t, name, value)
|
||||
if not current or t ~= current[1] then
|
||||
current = {t, {name}, {value}}
|
||||
table.insert(assigns, current)
|
||||
else
|
||||
table.insert(current[2], name)
|
||||
table.insert(current[3], value)
|
||||
end
|
||||
end
|
||||
|
||||
for i, assignee in ipairs(names) do
|
||||
local name_value = self:value(assignee)
|
||||
local value = self:value(values[i])
|
||||
|
||||
if ntype(assignee) == "chain" or self:has_name(assignee) then
|
||||
append("non-local", name_value, value)
|
||||
else
|
||||
append("local", name_value, value)
|
||||
end
|
||||
|
||||
if type(assignee) == "string" then
|
||||
self:put_name(assignee)
|
||||
end
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
for _, group in ipairs(assigns) do
|
||||
local t, names, values = unpack(group)
|
||||
if #values == 0 then values = {"nil"} end
|
||||
local line = table.concat(names, ", ").." = "..table.concat(values, ", ")
|
||||
table.insert(lines, t == "local" and "local "..line or line)
|
||||
end
|
||||
return table.concat(lines, "\n"..self:ichar())
|
||||
end,
|
||||
|
||||
exp = function(self, node)
|
||||
@ -90,8 +157,7 @@ local compilers = {
|
||||
|
||||
value = function(self, node)
|
||||
if type(node) == "table" then
|
||||
local op = unpack(node)
|
||||
return self[op](self, node)
|
||||
return self[node[1]](self, node)
|
||||
end
|
||||
|
||||
return node
|
||||
|
@ -140,6 +140,16 @@ local build_grammar = wrap(function()
|
||||
return {"chain", callee, args}
|
||||
end
|
||||
|
||||
-- makes sure the last item in a chain is an index
|
||||
local function check_assignable(str, pos, value)
|
||||
if ntype(value) == "chain" and ntype(value[#value]) == "index"
|
||||
or type(value) == "string"
|
||||
then
|
||||
return true, value
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- make sure name is not a keyword
|
||||
local Name = Cmt(Name, function(str, pos, name)
|
||||
if keywords[name] then return false end
|
||||
@ -160,18 +170,21 @@ local build_grammar = wrap(function()
|
||||
|
||||
If = key"if" * Exp * Body / mark"if",
|
||||
|
||||
Assign = Ct(NameList) * sym"=" * Ct(ExpList) / mark"assign",
|
||||
Assign = Ct(AssignableList) * sym"=" * Ct(ExpList) / mark"assign",
|
||||
|
||||
Assignable = Cmt(Chain, check_assignable) + Name,
|
||||
AssignableList = Assignable * (sym"," * Assignable)^0,
|
||||
|
||||
Exp = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp",
|
||||
Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp",
|
||||
|
||||
Value = Assign + FunLit + (FunCall + Callable) * Ct(ExpList^0) / flatten_func + Num,
|
||||
Value = Assign + FunLit + (Chain + Callable) * Ct(ExpList^0) / flatten_func + Num,
|
||||
|
||||
Callable = Name + Parens,
|
||||
Parens = sym"(" * Exp * sym")",
|
||||
|
||||
-- a plain function/index
|
||||
FunCall = Callable * (symx"(" * Ct(ExpList^-1)/mark"call" * sym")" + symx"[" * Exp/mark"index" * sym"]")^1 / mark"chain",
|
||||
-- a list of funcalls and indexs on a callable
|
||||
Chain = Callable * (symx"(" * Ct(ExpList^-1)/mark"call" * sym")" + symx"[" * Exp/mark"index" * sym"]")^1 / mark"chain",
|
||||
|
||||
TableLit = sym"{" * Ct(ExpList^-1) * sym"}" / mark"list",
|
||||
|
||||
|
16
tests/inputs/assign.moon
Normal file
16
tests/inputs/assign.moon
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
->
|
||||
joop = 2302
|
||||
|
||||
(hi) ->
|
||||
d = 100
|
||||
hi = 1021
|
||||
|
||||
a,b,c,d = 1,2,3,4
|
||||
|
||||
hello[232], (5+5)[121], hello, x[99] = 100, 200, 300
|
||||
|
||||
joop = 12
|
||||
|
||||
joop = 2345
|
||||
|
14
tests/outputs/assign.lua
Normal file
14
tests/outputs/assign.lua
Normal file
@ -0,0 +1,14 @@
|
||||
function()
|
||||
local joop = 2302
|
||||
function(hi)
|
||||
local d = 100
|
||||
hi = 1021
|
||||
local a, b, c = 1, 2, 3
|
||||
d = 4
|
||||
hello[232], (5 + 5)[121] = 100, 200
|
||||
local hello = 300
|
||||
x[99] = nil
|
||||
joop = 12
|
||||
end
|
||||
end
|
||||
local joop = 2345
|
@ -10,9 +10,11 @@ end)
|
||||
local h = function() hi end
|
||||
eat(function() end, world)
|
||||
local a = 1 + 2 * 3 / 6
|
||||
local a, bunch, go, here = another, world
|
||||
a = another
|
||||
local bunch, go, here = world
|
||||
func(arg(1, arg(2, another, arg(3))))
|
||||
local here, we = function() end, yeah
|
||||
here = function() end
|
||||
local we = yeah
|
||||
local the, different = function() approach end, yeah
|
||||
dad()
|
||||
dad(lord)
|
||||
|
Loading…
Reference in New Issue
Block a user