From 361feef82554837b55a5dbf04d20c6ea82e2e56a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 23 Jun 2011 08:42:43 -0700 Subject: [PATCH] slice shorthand for unpacked list comprehension --- moonscript/compile/line.lua | 41 +++++++++++++++++++++--- moonscript/compile/line.moon | 32 +++++++++++++++---- moonscript/parse.lua | 17 +++++++--- tests/inputs/lists.moon | 9 ++++++ tests/outputs/lists.lua | 60 ++++++++++++++++++++++++++++-------- 5 files changed, 132 insertions(+), 27 deletions(-) diff --git a/moonscript/compile/line.lua b/moonscript/compile/line.lua index bf52282..99a13ad 100644 --- a/moonscript/compile/line.lua +++ b/moonscript/compile/line.lua @@ -7,6 +7,8 @@ local reversed = util.reversed local ntype = data.ntype local concat, insert = table.concat, table.insert local constructor_name = "new" +local is_slice +is_slice = function(node) return ntype(node) == "chain" and ntype(node[#node]) == "slice" end line_compile = { raw = function(self, node) local _, text = unpack(node) @@ -341,17 +343,46 @@ line_compile = { end)(), ", ") if ntype(iter) == "unpack" then iter = iter[2] - local items_tmp = self:free_name("item") - local index_tmp = self:free_name("index") + local items_tmp = action:free_name("item") + local index_tmp = action:free_name("index") + local max_tmp = nil insert(self._lines, 1, ("local %s = %s[%s]"):format(name_list, items_tmp, index_tmp)) + local min, max, skip = 1, ("#%s"):format(items_tmp, nil) + if is_slice(iter) then + local slice = iter[#iter] + table.remove(iter) + min = action:value(slice[2]) + if slice[3] and slice[3] ~= "" then + max_tmp = action:free_name("max", true) + action:stm({ "assign", { max_tmp }, { slice[3] } }) + max = action:value({ + "exp", + max_tmp, + "<", + 0, + "and", + { + "exp", + { "length", items_tmp }, + "+", + max_tmp + }, + "or", + max_tmp + }) + end + if slice[4] then + skip = action:value(slice[4]) + end + end return action:add_lines({ - ("local %s = %s"):format(items_tmp, self:value(iter)), - ("for %s=1,#%s do"):format(index_tmp, items_tmp), + ("local %s = %s"):format(items_tmp, action:value(iter)), + ("for %s=%s do"):format(index_tmp, concat({ min, max, skip }, ",")), self:render(true), "end" }) else - return action:add_lines({ ("for %s in %s do"):format(name_list, self:value(iter)), self:render(true), "end" }) + return action:add_lines({ ("for %s in %s do"):format(name_list, action:value(iter)), self:render(true), "end" }) end elseif "when" == t then local cond diff --git a/moonscript/compile/line.moon b/moonscript/compile/line.moon index b545151..3e65620 100644 --- a/moonscript/compile/line.moon +++ b/moonscript/compile/line.moon @@ -14,6 +14,9 @@ export line_compile constructor_name = "new" +is_slice = (node) -> + ntype(node) == "chain" and ntype(node[#node]) == "slice" + line_compile = raw: (node) => _, text = unpack node @@ -260,7 +263,7 @@ line_compile = render_clause = (clause) => t = clause[1] - action = @block() + action = @block! action\set_indent @indent - 1 if "for" == t @@ -269,20 +272,37 @@ line_compile = if ntype(iter) == "unpack" iter = iter[2] - items_tmp = @free_name "item" - index_tmp = @free_name "index" + items_tmp = action\free_name "item" + index_tmp = action\free_name "index" + max_tmp = nil insert self._lines, 1, ("local %s = %s[%s]")\format name_list, items_tmp, index_tmp + -- slice shortcut + min, max, skip = 1, ("#%s")\format items_tmp, nil + if is_slice iter + slice = iter[#iter] + table.remove iter + min = action\value slice[2] + if slice[3] and slice[3] != "" + max_tmp = action\free_name "max", true + action\stm {"assign", {max_tmp}, {slice[3]}} + max = action\value {"exp", max_tmp, "<", 0 + "and", {"exp", {"length", items_tmp}, "+", max_tmp} + "or", max_tmp + } + if slice[4] + skip = action\value slice[4] + action\add_lines { - ("local %s = %s")\format items_tmp, @value iter - ("for %s=1,#%s do")\format index_tmp, items_tmp + ("local %s = %s")\format items_tmp, action\value iter + ("for %s=%s do")\format index_tmp, concat {min, max, skip}, "," @render true "end" } else action\add_lines { - ("for %s in %s do")\format(name_list, @value iter) + ("for %s in %s do")\format name_list, action\value iter @render true "end" } diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f4406a2..831b068 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -280,7 +280,7 @@ local build_grammar = wrap(function() -- Factor = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp", -- Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp", - Value = + SimpleValue = If + sym"-" * -SomeSpace * Exp / mark"minus" + sym"#" * Exp / mark"length" + @@ -288,11 +288,19 @@ local build_grammar = wrap(function() TableLit + Comprehension + ColonChain * Ct(ExpList^0) / flatten_func + -- have precedence over open table - Ct(KeyValueList) / mark"table" + Assign + Update + FunLit + String + - ((Chain + DotChain + Callable) * Ct(ExpList^0)) / flatten_func + Num, + ChainValue = + ((Chain + DotChain + Callable) * Ct(ExpList^0)) / flatten_func, + + Value = + SimpleValue + + Ct(KeyValueList) / mark"table" + + ChainValue, + + SliceValue = SimpleValue + ChainValue, + String = Space * DoubleString + Space * SingleString + LuaString, SingleString = simple_string("'"), DoubleString = simple_string('"'), @@ -331,7 +339,8 @@ local build_grammar = wrap(function() symx"." * _Name/mark"dot" + ColonCall, - Slice = symx"[" * Num * sym":" * Num * (sym":" * Num)^-1 *sym"]" / mark"slice", + Slice = symx"[" * (SliceValue + Cc(1)) * sym":" * (SliceValue + Cc"") * + (sym":" * SliceValue)^-1 *sym"]" / mark"slice", ColonCall = symx"\\" * (_Name * Invoke) / mark"colon", ColonSuffix = symx"\\" * _Name / mark"colon_stub", diff --git a/tests/inputs/lists.moon b/tests/inputs/lists.moon index d0965ec..f69dcc2 100644 --- a/tests/inputs/lists.moon +++ b/tests/inputs/lists.moon @@ -49,3 +49,12 @@ hello = [x + y for x in *items for y in *items] print z for z in *hello + +-- slice +x = {1, 2, 3, 4, 5, 6, 7} +print y for y in *x[2:-5:2] +print y for y in *x[:3] +print y for y in *x[2:] +print y for y in *x[::2] +print y for y in *x[2::2] + diff --git a/tests/outputs/lists.lua b/tests/outputs/lists.lua index 7fcd0e6..c38ca17 100644 --- a/tests/outputs/lists.lua +++ b/tests/outputs/lists.lua @@ -1,11 +1,11 @@ local hi = (function() local _moon_0 = {} for _, x in ipairs({ - 1, - 2, - 3, - 4 - }) do + 1, + 2, + 3, + 4 + }) do table.insert(_moon_0, x * 2) end return _moon_0 @@ -33,13 +33,13 @@ end local rad = (function() local _moon_0 = {} for a in ipairs({ - 1, - 2, - 3, - 4, - 5, - 6 - }) do + 1, + 2, + 3, + 4, + 5, + 6 + }) do if good_number(a) then table.insert(_moon_0, { a }) end @@ -166,4 +166,40 @@ local _item_0 = hello for _index_0=1,#_item_0 do local z = _item_0[_index_0] print(z) +end +x = { + 1, + 2, + 3, + 4, + 5, + 6, + 7 +} +local _max_0 = -5 +local _item_0 = x +for _index_0=2,_max_0 < 0 and #_item_0 + _max_0 or _max_0,2 do + local y = _item_0[_index_0] + print(y) +end +local _max_0 = 3 +local _item_0 = x +for _index_0=1,_max_0 < 0 and #_item_0 + _max_0 or _max_0 do + local y = _item_0[_index_0] + print(y) +end +local _item_0 = x +for _index_0=2,#_item_0 do + local y = _item_0[_index_0] + print(y) +end +local _item_0 = x +for _index_0=1,#_item_0,2 do + local y = _item_0[_index_0] + print(y) +end +local _item_0 = x +for _index_0=2,#_item_0,2 do + local y = _item_0[_index_0] + print(y) end \ No newline at end of file