assignment and scoping functional

This commit is contained in:
leaf corcoran 2011-05-21 22:00:31 -07:00
parent 4936446f1c
commit 4d489581ba
5 changed files with 127 additions and 16 deletions

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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)