From 0cf96b97f64ee4e3de95e72b1e96f0904775abe7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 15:09:17 -0800 Subject: [PATCH] add numeric for loop comprehensions/decorator, fixes #45 --- docs/reference.md | 6 +++ moonscript/parse.lua | 7 +-- moonscript/transform.lua | 70 ++++++++++++++++++++------- moonscript/transform.moon | 21 ++++---- tests/inputs/comprehension.moon | 14 ++++++ tests/inputs/syntax.moon | 1 + tests/outputs/comprehension.lua | 85 ++++++++++++++++++++++++++++++++- tests/outputs/syntax.lua | 3 ++ 8 files changed, 177 insertions(+), 30 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 5310781..c5549f6 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -415,6 +415,12 @@ Using multiple `for` clauses is the same as using nested loops: points = [{x,y} for x in *x_coords for y in *y_coords] ``` +Numeric for loops can also be used in comprehensions: + + ```moon + evens = [i for i=1,100 when i % 2 == 0] + ``` + ### Table Comprehensions The syntax for table comprehensions is very similar, only differing by using `{` and diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 23ae998..6a506cc 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -447,9 +447,10 @@ local build_grammar = wrap_env(function() 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", - CompClause = CompFor + key"when" * Exp / mark"when", + CompInner = Ct((CompForEach + CompFor) * CompClause^0), + CompForEach = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"foreach", + CompFor = key "for" * Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1) / mark"for", + CompClause = CompFor + CompForEach + key"when" * Exp / mark"when", Assign = sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign", Update = ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=" + sym"or=" + sym"and=") / trim) * Exp / mark"update", diff --git a/moonscript/transform.lua b/moonscript/transform.lua index db428b5..ed4c881 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -66,12 +66,16 @@ apply_to_last = function(stms, fn) local _accum_0 = { } local _len_0 = 1 for i, stm in ipairs(stms) do + local _value_0 if i == last_exp_id then - _accum_0[_len_0] = fn(stm) + _value_0 = fn(stm) else - _accum_0[_len_0] = stm + _value_0 = stm + end + if _value_0 ~= nil then + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end - _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -291,9 +295,25 @@ construct_comprehension = function(inner, clauses) local current_stms = inner for _, clause in reversed(clauses) do local t = clause[1] - if t == "for" then + local _exp_0 = t + if "for" == _exp_0 then + local name, bounds + do + local _obj_0 = clause + _, name, bounds = _obj_0[1], _obj_0[2], _obj_0[3] + end + current_stms = { + "for", + name, + bounds, + current_stms + } + elseif "foreach" == _exp_0 then local names, iter - _, names, iter = unpack(clause) + do + local _obj_0 = clause + _, names, iter = _obj_0[1], _obj_0[2], _obj_0[3] + end current_stms = { "foreach", names, @@ -302,9 +322,12 @@ construct_comprehension = function(inner, clauses) }, current_stms } - elseif t == "when" then + elseif "when" == _exp_0 then local cond - _, cond = unpack(clause) + do + local _obj_0 = clause + _, cond = _obj_0[1], _obj_0[2] + end current_stms = { "if", cond, @@ -440,15 +463,19 @@ local Statement = Transformer({ local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] + local _value_0 if type(name) == "table" then - _accum_0[_len_0] = name + _value_0 = name else - _accum_0[_len_0] = { + _value_0 = { "dot", name } end - _len_0 = _len_0 + 1 + if _value_0 ~= nil then + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end end return _accum_0 end)() @@ -458,8 +485,11 @@ local Statement = Transformer({ local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - _accum_0[_len_0] = type(name) == "table" and name[2] or name - _len_0 = _len_0 + 1 + local _value_0 = type(name) == "table" and name[2] or name + if _value_0 ~= nil then + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end end return _accum_0 end)() @@ -681,17 +711,21 @@ local Statement = Transformer({ local _accum_0 = { } local _len_0 = 1 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 insert(destructures, destructure.build_assign(name, proxy)) - _accum_0[_len_0] = _with_0 + _value_0 = _with_0 end else - _accum_0[_len_0] = name + _value_0 = name + end + if _value_0 ~= nil then + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end - _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -872,8 +906,10 @@ local Statement = Transformer({ else _value_0 = tuple end - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + if _value_0 ~= nil then + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end _continue_0 = true until true if not _continue_0 then diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 8901cbb..d27b6e2 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -140,14 +140,19 @@ construct_comprehension = (inner, clauses) -> current_stms = inner for _, clause in reversed clauses t = clause[1] - current_stms = if t == "for" - _, names, iter = unpack clause - {"foreach", names, {iter}, current_stms} - elseif t == "when" - _, cond = unpack clause - {"if", cond, current_stms} - else - error "Unknown comprehension clause: "..t + current_stms = switch t + when "for" + {_, name, bounds} = clause + {"for", name, bounds, current_stms} + when "foreach" + {_, names, iter} = clause + {"foreach", names, {iter}, current_stms} + when "when" + {_, cond} = clause + {"if", cond, current_stms} + else + error "Unknown comprehension clause: "..t + current_stms = {current_stms} current_stms[1] diff --git a/tests/inputs/comprehension.moon b/tests/inputs/comprehension.moon index 6822c84..345d5b7 100644 --- a/tests/inputs/comprehension.moon +++ b/tests/inputs/comprehension.moon @@ -17,3 +17,17 @@ copy = {k,v for k,v in pairs x when k != "okay"} { xxxx for x in yes } { unpack [a*i for i, a in ipairs x] for x in *{{1,2}, {3,4}} } + +-- + +n1 = [i for i=1,10] +n2 = [i for i=1,10 when i % 2 == 1] + +aa = [{x,y} for x=1,10 for y=5,14] +bb = [y for thing in y for i=1,10] +cc = [y for i=1,10 for thing in y] +dd = [y for i=1,10 when cool for thing in y when x > 3 when c + 3] + +{"hello", "world" for i=1,10} + +nil diff --git a/tests/inputs/syntax.moon b/tests/inputs/syntax.moon index 262945c..6e3a09b 100644 --- a/tests/inputs/syntax.moon +++ b/tests/inputs/syntax.moon @@ -104,6 +104,7 @@ x = -[x for x in x] print "hello" if cool print "hello" unless cool print "hello" unless 1212 and 3434 -- hello +print "hello" for i=1,10 print "nutjob" diff --git a/tests/outputs/comprehension.lua b/tests/outputs/comprehension.lua index 0598efe..4ac5530 100644 --- a/tests/outputs/comprehension.lua +++ b/tests/outputs/comprehension.lua @@ -52,7 +52,7 @@ _ = (function() end return _tbl_0 end)() -return (function() +_ = (function() local _tbl_0 = { } local _list_0 = { { @@ -78,4 +78,85 @@ return (function() _tbl_0[_key_0] = _val_0 end return _tbl_0 -end)() \ No newline at end of file +end)() +local n1 = (function() + local _accum_0 = { } + local _len_0 = 1 + for i = 1, 10 do + _accum_0[_len_0] = i + _len_0 = _len_0 + 1 + end + return _accum_0 +end)() +local n2 = (function() + local _accum_0 = { } + local _len_0 = 1 + for i = 1, 10 do + if i % 2 == 1 then + _accum_0[_len_0] = i + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end)() +local aa = (function() + local _accum_0 = { } + local _len_0 = 1 + for x = 1, 10 do + for y = 5, 14 do + _accum_0[_len_0] = { + x, + y + } + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end)() +local bb = (function() + local _accum_0 = { } + local _len_0 = 1 + for thing in y do + for i = 1, 10 do + _accum_0[_len_0] = y + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end)() +local cc = (function() + local _accum_0 = { } + local _len_0 = 1 + for i = 1, 10 do + for thing in y do + _accum_0[_len_0] = y + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end)() +local dd = (function() + local _accum_0 = { } + local _len_0 = 1 + for i = 1, 10 do + if cool then + for thing in y do + if x > 3 then + if c + 3 then + _accum_0[_len_0] = y + _len_0 = _len_0 + 1 + end + end + end + end + end + return _accum_0 +end)() +_ = (function() + local _tbl_0 = { } + for i = 1, 10 do + _tbl_0["hello"] = "world" + end + return _tbl_0 +end)() +return nil \ No newline at end of file diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua index 75b5bc1..893787a 100644 --- a/tests/outputs/syntax.lua +++ b/tests/outputs/syntax.lua @@ -107,6 +107,9 @@ end if not (1212 and 3434) then print("hello") end +for i = 1, 10 do + print("hello") +end print("nutjob") if hello then _ = 343