From 14db695560a277d06882ecea2e29dbee8b550941 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 3 Oct 2012 11:30:23 -0700 Subject: [PATCH] table comprehensions support single expression that returns a pair --- docs/reference.md | 14 ++++++++- moonscript/parse.lua | 2 +- moonscript/transform.lua | 47 ++++++++++++++++++++++------- moonscript/transform.moon | 20 ++++++++++--- tests/inputs/comprehension.moon | 10 +++++++ tests/outputs/comprehension.lua | 53 +++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 17 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index e54133d..9aba307 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -436,6 +436,18 @@ for a few numbers. sqrts = {i, math.sqrt i for i in *numbers} ``` +The key-value tuple in a table comprehension can also come from a single +expression, in which case the expression should return two values. The +first is used as the key and the second is used as the value: + +In this example we convert an array of pairs to a table where the first item in +the pair is the key and the second is the value. + + ```moon + tuples = {{"hello", "world"}, {"foo", "bar"}} + tbl = {unpack tuple for tuple in *tuples} + ``` + ### Slicing A special syntax is provided to restrict the items that are iterated over when @@ -480,7 +492,7 @@ There are two for loop forms, just like in Lua. A numeric one and a generic one: print key, value ``` -The slicing and `*` operators can be used, just like with table comprehensions: +The slicing and `*` operators can be used, just like with comprehensions: ```moon for item in *items[2,4] diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 79f978b..9acbe09 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -413,7 +413,7 @@ local build_grammar = wrap_env(function() Comprehension = sym"[" * Exp * CompInner * sym"]" / mark"comprehension", - TblComprehension = sym"{" * Exp * (sym"," * Exp)^-1 * CompInner * sym"}" / mark"tblcomprehension", + TblComprehension = sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension", CompInner = Ct(CompFor * CompClause^0), CompFor = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"for", diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 67375c5..c8c940b 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1231,21 +1231,46 @@ Value = Transformer({ return a:wrap(node) end, tblcomprehension = function(self, node) - local _, key_exp, value_exp, clauses = unpack(node) + local _, explist, clauses = unpack(node) + local key_exp, value_exp = unpack(explist) local accum = NameProxy("tbl") - local dest = build.chain({ - base = accum, - { - "index", - key_exp + local inner + if value_exp then + local dest = build.chain({ + base = accum, + { + "index", + key_exp + } + }) + inner = { + build.assign_one(dest, value_exp) } - }) - local inner = build.assign_one(dest, value_exp) + else + local key_name, val_name = NameProxy("key"), NameProxy("val") + local dest = build.chain({ + base = accum, + { + "index", + key_name + } + }) + inner = { + build.assign({ + names = { + key_name, + val_name + }, + values = { + key_exp + } + }), + build.assign_one(dest, val_name) + } + end return build.block_exp({ build.assign_one(accum, build.table()), - construct_comprehension({ - inner - }, clauses), + construct_comprehension(inner, clauses), accum }) end, diff --git a/moonscript/transform.moon b/moonscript/transform.moon index d3a0594..1b46a94 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -654,15 +654,27 @@ Value = Transformer { a\wrap node tblcomprehension: (node) => - _, key_exp, value_exp, clauses = unpack node + _, explist, clauses = unpack node + key_exp, value_exp = unpack explist accum = NameProxy "tbl" - dest = build.chain { base: accum, {"index", key_exp} } - inner = build.assign_one dest, value_exp + + inner = if value_exp + dest = build.chain { base: accum, {"index", key_exp} } + { build.assign_one dest, value_exp } + else + -- If we only have single expression then + -- unpack the result into key and value + key_name, val_name = NameProxy"key", NameProxy"val" + dest = build.chain { base: accum, {"index", key_name} } + { + build.assign names: {key_name, val_name}, values: {key_exp} + build.assign_one dest, val_name + } build.block_exp { build.assign_one accum, build.table! - construct_comprehension {inner}, clauses + construct_comprehension inner, clauses accum } diff --git a/tests/inputs/comprehension.moon b/tests/inputs/comprehension.moon index ee0d662..6822c84 100644 --- a/tests/inputs/comprehension.moon +++ b/tests/inputs/comprehension.moon @@ -1,4 +1,6 @@ +-- see lists.moon for list comprehension tests + items = {1,2,3,4,5,6} out = {k,k*2 for k in items} @@ -7,3 +9,11 @@ x = hello: "world", okay: 2323 copy = {k,v for k,v in pairs x when k != "okay"} +-- + +{ unpack(x) for x in yes } +{ unpack(x) for x in *yes } + +{ xxxx for x in yes } +{ unpack [a*i for i, a in ipairs x] for x in *{{1,2}, {3,4}} } + diff --git a/tests/outputs/comprehension.lua b/tests/outputs/comprehension.lua index e1c38b4..b1bf218 100644 --- a/tests/outputs/comprehension.lua +++ b/tests/outputs/comprehension.lua @@ -25,4 +25,57 @@ local copy = (function() end end return _tbl_0 +end)() +local _ = (function() + local _tbl_0 = { } + for x in yes do + local _key_0, _val_0 = unpack(x) + _tbl_0[_key_0] = _val_0 + end + return _tbl_0 +end)() +_ = (function() + local _tbl_0 = { } + local _list_0 = yes + for _index_0 = 1, #_list_0 do + x = _list_0[_index_0] + local _key_0, _val_0 = unpack(x) + _tbl_0[_key_0] = _val_0 + end + return _tbl_0 +end)() +_ = (function() + local _tbl_0 = { } + for x in yes do + local _key_0, _val_0 = xxxx + _tbl_0[_key_0] = _val_0 + end + return _tbl_0 +end)() +_ = (function() + local _tbl_0 = { } + local _list_0 = { + { + 1, + 2 + }, + { + 3, + 4 + } + } + for _index_0 = 1, #_list_0 do + x = _list_0[_index_0] + local _key_0, _val_0 = unpack((function() + local _accum_0 = { } + local _len_0 = 0 + for i, a in ipairs(x) do + _len_0 = _len_0 + 1 + _accum_0[_len_0] = a * i + end + return _accum_0 + end)()) + _tbl_0[_key_0] = _val_0 + end + return _tbl_0 end)() \ No newline at end of file