allow destructure in for in names

This commit is contained in:
leaf corcoran 2012-11-29 00:37:49 -08:00
parent 7498a52aee
commit 25b997e71f
9 changed files with 179 additions and 78 deletions

View File

@ -435,7 +435,7 @@ local build_grammar = wrap_env(function()
For = key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) *
key"do"^-1 * Body / mark"for",
ForEach = key"for" * Ct(NameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach",
ForEach = key"for" * Ct(AssignableNameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach",
Do = key"do" * Body / mark"do",
@ -575,7 +575,7 @@ local build_grammar = wrap_env(function()
(key"using" * Ct(NameList + Space * "nil") + Ct"") *
sym")" + Ct"" * Ct"",
FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0,
FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0,
FnArgDef = Ct(Name * (sym"=" * Exp)^-1),
FunLit = FnArgsDef *
@ -583,6 +583,9 @@ local build_grammar = wrap_env(function()
(Body + Ct"") / mark"fndef",
NameList = Name * (sym"," * Name)^0,
NameOrDestructure = Name + TableLit,
AssignableNameList = NameOrDestructure * (sym"," * NameOrDestructure)^0,
ExpList = Exp * (sym"," * Exp)^0,
ExpListLow = Exp * ((sym"," + sym";") * Exp)^0,

View File

@ -2,7 +2,7 @@ local types = require("moonscript.types")
local util = require("moonscript.util")
local data = require("moonscript.data")
local reversed = util.reversed
local ntype, build, smart_node, is_slice, value_is_singular = types.ntype, types.build, types.smart_node, types.is_slice, types.value_is_singular
local ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular
local insert = table.insert
local NameProxy, LocalName
do
@ -10,18 +10,6 @@ do
NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName
end
local destructure = require("moonscript.transform.destructure")
local mtype
do
local moon_type = util.moon.type
mtype = function(val)
local t = type(val)
if "table" == t and rawget(val, "__class") then
return moon_type(val)
else
return t
end
end
end
local implicitly_return
local Run
do
@ -670,6 +658,34 @@ local Statement = Transformer({
foreach = function(self, node)
smart_node(node)
local source = unpack(node.iter)
local destructures = { }
node.names = (function()
local _accum_0 = { }
local _len_0 = 0
for i, name in ipairs(node.names) do
local _value_0
if ntype(name) == "table" then
do
local _with_0 = NameProxy("des")
local proxy = _with_0
local extracted = destructure.extract_assign_names(name)
insert(destructures, destructure.build_assign(extracted, proxy))
_value_0 = _with_0
end
else
_value_0 = name
end
if _value_0 ~= nil then
_len_0 = _len_0 + 1
_accum_0[_len_0] = _value_0
end
end
return _accum_0
end)()
if next(destructures) then
insert(destructures, build.group(node.body))
node.body = destructures
end
if ntype(source) == "unpack" then
local list = source[2]
local index_name = NameProxy("index")

View File

@ -4,22 +4,12 @@ util = require "moonscript.util"
data = require "moonscript.data"
import reversed from util
import ntype, build, smart_node, is_slice, value_is_singular from types
import ntype, mtype, build, smart_node, is_slice, value_is_singular from types
import insert from table
import NameProxy, LocalName from require "moonscript.transform.names"
destructure = require "moonscript.transform.destructure"
mtype = do
moon_type = util.moon.type
-- lets us check a smart node without throwing an error
(val) ->
t = type(val)
if "table" == t and rawget(val, "__class")
moon_type val
else
t
local implicitly_return
class Run
@ -347,6 +337,19 @@ Statement = Transformer {
smart_node node
source = unpack node.iter
destructures = {}
node.names = for i, name in ipairs node.names
if ntype(name) == "table"
with proxy = NameProxy "des"
extracted = destructure.extract_assign_names name
insert destructures, destructure.build_assign extracted, proxy
else
name
if next destructures
insert destructures, build.group node.body
node.body = destructures
if ntype(source) == "unpack"
list = source[2]

View File

@ -1,7 +1,7 @@
local ntype, build
local ntype, mtype, build
do
local _table_0 = require("moonscript.types")
ntype, build = _table_0.ntype, _table_0.build
ntype, mtype, build = _table_0.ntype, _table_0.mtype, _table_0.build
end
local NameProxy
do
@ -48,9 +48,31 @@ has_destructure = function(names)
end
local build_assign
build_assign = function(extracted_names, receiver)
local obj = NameProxy("obj")
local names = { }
local values = { }
local inner = {
"assign",
names,
values
}
local obj
if mtype(receiver) == NameProxy then
obj = receiver
else
do
local _with_0 = NameProxy("obj")
obj = _with_0
inner = build["do"]({
build.assign_one(obj, receiver),
{
"assign",
names,
values
}
})
obj = _with_0
end
end
local _list_0 = extracted_names
for _index_0 = 1, #_list_0 do
local tuple = _list_0[_index_0]
@ -62,14 +84,7 @@ build_assign = function(extracted_names, receiver)
"declare",
names
},
build["do"]({
build.assign_one(obj, receiver),
{
"assign",
names,
values
}
})
inner
})
end
local extract_assign_names

View File

@ -1,5 +1,5 @@
import ntype, build from require "moonscript.types"
import ntype, mtype, build from require "moonscript.types"
import NameProxy from require "moonscript.transform.names"
import insert from table
@ -19,20 +19,27 @@ has_destructure = (names) ->
false
build_assign = (extracted_names, receiver) ->
obj = NameProxy "obj"
names = {}
values = {}
inner = {"assign", names, values}
obj = if mtype(receiver) == NameProxy
receiver
else
with obj = NameProxy "obj"
inner = build.do {
build.assign_one obj, receiver
{"assign", names, values}
}
for tuple in *extracted_names
insert names, tuple[1]
insert values, obj\chain unpack tuple[2]
build.group {
{"declare", names}
build.do {
build.assign_one obj, receiver
{"assign", names, values}
}
inner
}
extract_assign_names = (name, accum={}, prefix={}) ->

View File

@ -26,6 +26,17 @@ ntype = function(node)
return "value"
end
end
local mtype
do
local moon_type = util.moon.type
mtype = function(val)
local mt = getmetatable(val)
if mt and mt.smart_node then
return "table"
end
return moon_type(val)
end
end
local has_value
has_value = function(node)
if ntype(node) == "chain" then
@ -260,27 +271,32 @@ build = setmetatable({
return rawget(self, name)
end
})
local smart_node_mt = setmetatable({ }, {
__index = function(self, node_type)
local index = key_table[node_type]
local mt = {
smart_node = true,
__index = function(node, key)
if index[key] then
return rawget(node, index[key])
elseif type(key) == "string" then
return error("unknown key: `" .. key .. "` on node type: `" .. ntype(node) .. "`")
end
end,
__newindex = function(node, key, value)
if index[key] then
key = index[key]
end
return rawset(node, key, value)
end
}
self[node_type] = mt
return mt
end
})
local smart_node
smart_node = function(node)
local index = key_table[ntype(node)]
if not index then
return node
end
return setmetatable(node, {
__index = function(node, key)
if index[key] then
return rawget(node, index[key])
elseif type(key) == "string" then
return error("unknown key: `" .. key .. "` on node type: `" .. ntype(node) .. "`")
end
end,
__newindex = function(node, key, value)
if index[key] then
key = index[key]
end
return rawset(node, key, value)
end
})
return setmetatable(node, smart_node_mt[ntype(node)])
end
return {
ntype = ntype,
@ -292,5 +308,6 @@ return {
cascading = cascading,
value_is_singular = value_is_singular,
comprehension_has_value = comprehension_has_value,
has_value = has_value
has_value = has_value,
mtype = mtype
}

View File

@ -22,6 +22,14 @@ ntype = (node) ->
else
"value"
mtype = do
moon_type = util.moon.type
-- lets us check a smart node without throwing an error
(val) ->
mt = getmetatable val
return "table" if mt and mt.smart_node
moon_type val
-- does this always return a value
has_value = (node) ->
if ntype(node) == "chain"
@ -142,25 +150,33 @@ build = setmetatable {
rawget self, name
}
smart_node_mt = setmetatable {}, {
__index: (node_type) =>
index = key_table[node_type]
mt = {
smart_node: true
__index: (node, key) ->
if index[key]
rawget node, index[key]
elseif type(key) == "string"
error "unknown key: `"..key.."` on node type: `"..ntype(node).. "`"
__newindex: (node, key, value) ->
key = index[key] if index[key]
rawset node, key, value
}
self[node_type] = mt
mt
}
-- makes it so node properties can be accessed by name instead of index
smart_node = (node) ->
index = key_table[ntype node]
if not index then return node
setmetatable node, {
__index: (node, key) ->
if index[key]
rawget node, index[key]
elseif type(key) == "string"
error "unknown key: `"..key.."` on node type: `"..ntype(node).. "`"
__newindex: (node, key, value) ->
key = index[key] if index[key]
rawset node, key, value
}
setmetatable node, smart_node_mt[ntype node]
{
:ntype, :smart_node, :build, :is_value, :is_slice, :manual_return,
:cascading, :value_is_singular, :comprehension_has_value, :has_value
:cascading, :value_is_singular, :comprehension_has_value, :has_value,
:mtype
}

View File

@ -43,3 +43,11 @@ print name, street, city
{ world: @world } = x
--
thing = {{1,2}, {3,4}}
for {x,y} in *thing
print x,y

View File

@ -85,4 +85,20 @@ end
do
local _obj_0 = x
self.world = _obj_0.world
end
thing = {
{
1,
2
},
{
3,
4
}
}
local _list_0 = thing
for _index_0 = 1, #_list_0 do
local _des_0 = _list_0[_index_0]
x, y = _des_0[1], _des_0[2]
print(x, y)
end