mirror of
https://github.com/leafo/moonscript.git
synced 2025-01-09 00:04:22 +00:00
for loops and while statements as expressions
This commit is contained in:
parent
9c000857fc
commit
1ea8f3fb6f
@ -195,6 +195,38 @@ single line:
|
||||
|
||||
for j = 1,10,3 do print j
|
||||
|
||||
A for loop can also be used an expression. The last statement in the body of
|
||||
the for loop is coerced into an expression and appended to an accumulating
|
||||
table if the value of that expression is not nil.
|
||||
|
||||
Doubling every even number:
|
||||
|
||||
doubled_evens = for i=1,20
|
||||
if i % 2 == 0
|
||||
i * 2
|
||||
else
|
||||
i
|
||||
|
||||
Filtering out odd numbers:
|
||||
|
||||
my_numbers = {1,2,3,4,5,6}
|
||||
odds = for x in *my_numbers
|
||||
if x % 2 == 1 then x
|
||||
|
||||
For loops at the end of a function body are not accumulated into a table for a
|
||||
return value (Instead the function will return `nil`). Either an explicit
|
||||
`return` statement can be used, or the loop can be converted into a list
|
||||
comprehension.
|
||||
|
||||
func_a -> for i=1,10 do i
|
||||
func_b -> return for i=1,10 do i
|
||||
|
||||
print func_a! -- prints nil
|
||||
print func_b! -- prints table object
|
||||
|
||||
This is done to avoid the needless creation of tables for functions that don't
|
||||
need to return the results of the loop.
|
||||
|
||||
## While Loop
|
||||
|
||||
The while loop also comes in two variations:
|
||||
@ -206,6 +238,10 @@ The while loop also comes in two variations:
|
||||
|
||||
while running == true do my_function!
|
||||
|
||||
Like for loops, the while loop can also be used an expression. Additionally,
|
||||
for a function to return the accumlated value of a while loop, the statement
|
||||
must be explicitly returned.
|
||||
|
||||
## Conditionals
|
||||
|
||||
have_coins = false
|
||||
|
@ -304,7 +304,7 @@ Block_ = (function(_parent_0)
|
||||
end,
|
||||
ret_stms = function(self, stms, ret)
|
||||
if not ret then
|
||||
ret = returner
|
||||
ret = default_return
|
||||
end
|
||||
local i = 1
|
||||
while i < #stms do
|
||||
|
@ -205,7 +205,7 @@ class Block_
|
||||
|
||||
ret_stms: (stms, ret) =>
|
||||
if not ret
|
||||
ret = returner
|
||||
ret = default_return
|
||||
|
||||
-- wow I really need a for loop
|
||||
i = 1
|
||||
|
@ -11,8 +11,14 @@ user_error = function(...)
|
||||
...
|
||||
})
|
||||
end
|
||||
returner = function(exp)
|
||||
if ntype(exp) == "chain" and exp[2] == "return" then
|
||||
local manual_return = Set({
|
||||
"foreach",
|
||||
"for",
|
||||
"while"
|
||||
})
|
||||
default_return = function(exp)
|
||||
local t = ntype(exp)
|
||||
if t == "chain" and exp[2] == "return" then
|
||||
local items = {
|
||||
"explist"
|
||||
}
|
||||
@ -27,6 +33,8 @@ returner = function(exp)
|
||||
"return",
|
||||
items
|
||||
}
|
||||
elseif manual_return[t] then
|
||||
return exp
|
||||
else
|
||||
return {
|
||||
"return",
|
||||
|
@ -7,7 +7,7 @@ import itwos from util
|
||||
import Set, ntype from data
|
||||
import concat, insert from table
|
||||
|
||||
export indent_char, returner, moonlib, cascading, non_atomic, has_value, is_non_atomic
|
||||
export indent_char, default_return, moonlib, cascading, non_atomic, has_value, is_non_atomic
|
||||
export count_lines, is_slice, user_error
|
||||
|
||||
indent_char = " "
|
||||
@ -15,12 +15,17 @@ indent_char = " "
|
||||
user_error = (...) ->
|
||||
error {"user-error", ...}
|
||||
|
||||
returner = (exp) ->
|
||||
if ntype(exp) == "chain" and exp[2] == "return"
|
||||
manual_return = Set{"foreach", "for", "while"}
|
||||
|
||||
default_return = (exp) ->
|
||||
t = ntype exp
|
||||
if t == "chain" and exp[2] == "return"
|
||||
-- extract the return
|
||||
items = {"explist"}
|
||||
insert items, v for v in *exp[3][2]
|
||||
{"return", items}
|
||||
elseif manual_return[t]
|
||||
exp
|
||||
else
|
||||
{"return", exp}
|
||||
|
||||
|
@ -35,8 +35,6 @@ line_compile = {
|
||||
end,
|
||||
assign = function(self, node)
|
||||
local _, names, values = unpack(node)
|
||||
local undeclared = self:declare(names)
|
||||
local declare = "local " .. concat(undeclared, ", ")
|
||||
if #values == 1 and cascading[ntype(values[1])] then
|
||||
return(self:stm({
|
||||
"assign",
|
||||
@ -44,6 +42,8 @@ line_compile = {
|
||||
values[1]
|
||||
}))
|
||||
end
|
||||
local undeclared = self:declare(names)
|
||||
local declare = "local " .. concat(undeclared, ", ")
|
||||
if self:is_stm(values) then
|
||||
if #undeclared > 0 then
|
||||
self:add(declare)
|
||||
|
@ -29,13 +29,13 @@ line_compile =
|
||||
assign: (node) =>
|
||||
_, names, values = unpack node
|
||||
|
||||
undeclared = @declare names
|
||||
declare = "local "..concat(undeclared, ", ")
|
||||
|
||||
-- can we extract single cascading value
|
||||
if #values == 1 and cascading[ntype values[1]]
|
||||
return @stm {"assign", names, values[1]}
|
||||
|
||||
undeclared = @declare names
|
||||
declare = "local "..concat(undeclared, ", ")
|
||||
|
||||
if @is_stm values
|
||||
@add declare if #undeclared > 0
|
||||
if cascading[ntype(values)]
|
||||
|
@ -5,6 +5,56 @@ local dump = require("moonscript.dump")
|
||||
require("moonscript.compile.format")
|
||||
local ntype = data.ntype
|
||||
local concat, insert = table.concat, table.insert
|
||||
local create_accumulate_wrapper
|
||||
create_accumulate_wrapper = function(block_pos)
|
||||
return function(self, node)
|
||||
do
|
||||
local _with_0 = self:block("(function()", "end)()")
|
||||
local accum_name = _with_0:init_free_var("accum", {
|
||||
"table"
|
||||
})
|
||||
local value_name = _with_0:free_name("value", true)
|
||||
local inner = node[block_pos]
|
||||
inner[#inner] = {
|
||||
"assign",
|
||||
{
|
||||
value_name
|
||||
},
|
||||
{
|
||||
inner[#inner]
|
||||
}
|
||||
}
|
||||
insert(inner, {
|
||||
"if",
|
||||
{
|
||||
"exp",
|
||||
value_name,
|
||||
"~=",
|
||||
"nil"
|
||||
},
|
||||
{
|
||||
{
|
||||
"chain",
|
||||
"table.insert",
|
||||
{
|
||||
"call",
|
||||
{
|
||||
accum_name,
|
||||
value_name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
_with_0:stm(node)
|
||||
_with_0:stm({
|
||||
"return",
|
||||
accum_name
|
||||
})
|
||||
return _with_0
|
||||
end
|
||||
end
|
||||
end
|
||||
value_compile = {
|
||||
exp = function(self, node)
|
||||
local _comp
|
||||
@ -60,14 +110,14 @@ value_compile = {
|
||||
with = function(self, node)
|
||||
do
|
||||
local _with_0 = self:block("(function()", "end)()")
|
||||
_with_0:stm(node, returner)
|
||||
_with_0:stm(node, default_return)
|
||||
return _with_0
|
||||
end
|
||||
end,
|
||||
["if"] = function(self, node)
|
||||
do
|
||||
local _with_0 = self:block("(function()", "end)()")
|
||||
_with_0:stm(node, returner)
|
||||
_with_0:stm(node, default_return)
|
||||
return _with_0
|
||||
end
|
||||
end,
|
||||
@ -100,6 +150,9 @@ value_compile = {
|
||||
return _with_0
|
||||
end
|
||||
end,
|
||||
["for"] = create_accumulate_wrapper(4),
|
||||
foreach = create_accumulate_wrapper(4),
|
||||
["while"] = create_accumulate_wrapper(3),
|
||||
chain = function(self, node)
|
||||
local callee = node[2]
|
||||
if callee == -1 then
|
||||
|
@ -12,6 +12,23 @@ import concat, insert from table
|
||||
|
||||
export value_compile
|
||||
|
||||
create_accumulate_wrapper = (block_pos) ->
|
||||
(node) =>
|
||||
with @block "(function()", "end)()"
|
||||
accum_name = \init_free_var "accum", {"table"}
|
||||
value_name = \free_name "value", true
|
||||
|
||||
inner = node[block_pos]
|
||||
inner[#inner] = {"assign", {value_name}, {inner[#inner]}}
|
||||
insert inner, {
|
||||
"if", {"exp", value_name, "~=", "nil"}, {
|
||||
{"chain", "table.insert", {"call", {accum_name, value_name}}}
|
||||
}
|
||||
}
|
||||
|
||||
\stm node
|
||||
\stm {"return", accum_name}
|
||||
|
||||
value_compile =
|
||||
exp: (node) =>
|
||||
_comp = (i, value) ->
|
||||
@ -40,11 +57,11 @@ value_compile =
|
||||
|
||||
with: (node) =>
|
||||
with @block "(function()", "end)()"
|
||||
\stm node, returner
|
||||
\stm node, default_return
|
||||
|
||||
if: (node) =>
|
||||
with @block "(function()", "end)()"
|
||||
\stm node, returner
|
||||
\stm node, default_return
|
||||
|
||||
comprehension: (node) =>
|
||||
exp = node[2]
|
||||
@ -58,6 +75,10 @@ value_compile =
|
||||
\stm node, action
|
||||
\stm {"return", tmp_name}
|
||||
|
||||
for: create_accumulate_wrapper 4
|
||||
foreach: create_accumulate_wrapper 4
|
||||
while: create_accumulate_wrapper 3
|
||||
|
||||
chain: (node) =>
|
||||
callee = node[2]
|
||||
|
||||
|
@ -244,7 +244,7 @@ local build_grammar = wrap(function()
|
||||
Block = Ct(Line * (Break^1 * Line)^0),
|
||||
Line = Cmt(Indent, check_indent) * Statement + _Space * Comment,
|
||||
|
||||
Statement = (Import + While + With + For + Foreach + Return
|
||||
Statement = (Import + While + With + For + ForEach + Return
|
||||
+ ClassDecl + Export + BreakLoop + Ct(ExpList) / flatten_or_mark"explist" * Space) * (
|
||||
-- statement decorators
|
||||
key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" +
|
||||
@ -277,7 +277,7 @@ local build_grammar = wrap(function()
|
||||
For = key"for" * (Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1)) *
|
||||
key"do"^-1 * Body / mark"for",
|
||||
|
||||
Foreach = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) * key"do"^-1 * Body / mark"foreach",
|
||||
ForEach = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) * key"do"^-1 * Body / mark"foreach",
|
||||
|
||||
Comprehension = sym"[" * Exp * CompInner * sym"]" / mark"comprehension",
|
||||
|
||||
@ -303,6 +303,7 @@ local build_grammar = wrap(function()
|
||||
SimpleValue =
|
||||
If +
|
||||
With +
|
||||
ForEach + For + While +
|
||||
sym"-" * -SomeSpace * Exp / mark"minus" +
|
||||
sym"#" * Exp / mark"length" +
|
||||
sym"not" * Exp / mark"not" +
|
||||
|
@ -21,16 +21,6 @@ if cool then wow cool else
|
||||
if working
|
||||
if cool then if cool then okay else what else nah
|
||||
|
||||
while true do print "name"
|
||||
|
||||
while 5 + 5
|
||||
print "okay world"
|
||||
working man
|
||||
|
||||
while also do
|
||||
i work too
|
||||
"okay"
|
||||
|
||||
|
||||
if yeah then no day elseif cool me then okay ya else u way
|
||||
if yeah then no dad else if cool you then okay bah else p way
|
||||
|
@ -28,4 +28,43 @@ x = ->
|
||||
for x in y
|
||||
y
|
||||
|
||||
hello = {1,2,3,4,5}
|
||||
|
||||
x = for y in *hello
|
||||
if y % 2 == 0
|
||||
y
|
||||
|
||||
x = ->
|
||||
for x in *hello
|
||||
y
|
||||
|
||||
t = for i=10,20 do i * 2
|
||||
|
||||
hmm = 0
|
||||
y = for j = 3,30, 8
|
||||
hmm += 1
|
||||
j * hmm
|
||||
|
||||
->
|
||||
for k=10,40
|
||||
"okay"
|
||||
|
||||
->
|
||||
return for k=10,40
|
||||
"okay"
|
||||
|
||||
while true do print "name"
|
||||
|
||||
while 5 + 5
|
||||
print "okay world"
|
||||
working man
|
||||
|
||||
while also do
|
||||
i work too
|
||||
"okay"
|
||||
|
||||
i = 0
|
||||
x = while i < 10
|
||||
i += 1
|
||||
|
||||
|
||||
|
@ -160,6 +160,8 @@ what whack - 5
|
||||
|
||||
x = hello - world - something
|
||||
|
||||
|
||||
((something = with what
|
||||
\cool 100) ->
|
||||
print something)!
|
||||
|
||||
|
||||
|
@ -20,3 +20,14 @@ with leaf
|
||||
|
||||
zyzyzy = with something
|
||||
.set_state "hello world"
|
||||
|
||||
|
||||
x = 5 + with Something!
|
||||
\write "hello world"
|
||||
|
||||
|
||||
x = {
|
||||
hello: with yeah
|
||||
\okay!
|
||||
}
|
||||
|
||||
|
@ -37,17 +37,6 @@ if working then
|
||||
local _ = nah
|
||||
end
|
||||
end
|
||||
while true do
|
||||
print("name")
|
||||
end
|
||||
while 5 + 5 do
|
||||
print("okay world")
|
||||
working(man)
|
||||
end
|
||||
while also do
|
||||
i(work(too))
|
||||
local _ = "okay"
|
||||
end
|
||||
if yeah then
|
||||
no(day)
|
||||
elseif cool(me) then
|
||||
|
@ -37,3 +37,99 @@ x = function()
|
||||
local _ = y
|
||||
end
|
||||
end
|
||||
local hello = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
}
|
||||
x = (function()
|
||||
local _accum_0 = { }
|
||||
do
|
||||
local _item_0 = hello
|
||||
for _index_0 = 1, #_item_0 do
|
||||
local y = _item_0[_index_0]
|
||||
local _value_0
|
||||
if y % 2 == 0 then
|
||||
_value_0 = y
|
||||
end
|
||||
if _value_0 ~= nil then
|
||||
table.insert(_accum_0, _value_0)
|
||||
end
|
||||
end
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
||||
x = function()
|
||||
do
|
||||
local _item_0 = hello
|
||||
for _index_0 = 1, #_item_0 do
|
||||
local x = _item_0[_index_0]
|
||||
local _ = y
|
||||
end
|
||||
end
|
||||
end
|
||||
local t = (function()
|
||||
local _accum_0 = { }
|
||||
for i = 10, 20 do
|
||||
local _value_0 = i * 2
|
||||
if _value_0 ~= nil then
|
||||
table.insert(_accum_0, _value_0)
|
||||
end
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
||||
local hmm = 0
|
||||
local y = (function()
|
||||
local _accum_0 = { }
|
||||
for j = 3, 30, 8 do
|
||||
hmm = hmm + 1
|
||||
local _value_0 = j * hmm
|
||||
if _value_0 ~= nil then
|
||||
table.insert(_accum_0, _value_0)
|
||||
end
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
||||
local _
|
||||
_ = function()
|
||||
for k = 10, 40 do
|
||||
_ = "okay"
|
||||
end
|
||||
end
|
||||
_ = function()
|
||||
return (function()
|
||||
local _accum_0 = { }
|
||||
for k = 10, 40 do
|
||||
local _value_0 = "okay"
|
||||
if _value_0 ~= nil then
|
||||
table.insert(_accum_0, _value_0)
|
||||
end
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
||||
end
|
||||
while true do
|
||||
print("name")
|
||||
end
|
||||
while 5 + 5 do
|
||||
print("okay world")
|
||||
working(man)
|
||||
end
|
||||
while also do
|
||||
i(work(too))
|
||||
_ = "okay"
|
||||
end
|
||||
local i = 0
|
||||
x = (function()
|
||||
local _accum_0 = { }
|
||||
while i < 10 do
|
||||
i = i + 1
|
||||
local _value_0 = i
|
||||
if _value_0 ~= nil then
|
||||
table.insert(_accum_0, _value_0)
|
||||
end
|
||||
end
|
||||
return _accum_0
|
||||
end)()
|
@ -165,3 +165,13 @@ what(whack + 5)
|
||||
_ = 5 - what(wack)
|
||||
what(whack - 5)
|
||||
x = hello - world - something
|
||||
(function(something)
|
||||
if something == nil then
|
||||
do
|
||||
local _with_0 = what
|
||||
_with_0:cool(100)
|
||||
something = _with_0
|
||||
end
|
||||
end
|
||||
return print(something)
|
||||
end)()
|
@ -24,3 +24,19 @@ do
|
||||
_with_0.set_state("hello world")
|
||||
zyzyzy = _with_0
|
||||
end
|
||||
local x = 5 + (function()
|
||||
do
|
||||
local _with_0 = Something()
|
||||
_with_0:write("hello world")
|
||||
return _with_0
|
||||
end
|
||||
end)()
|
||||
x = {
|
||||
hello = (function()
|
||||
do
|
||||
local _with_0 = yeah
|
||||
_with_0:okay()
|
||||
return _with_0
|
||||
end
|
||||
end)()
|
||||
}
|
2
todo
2
todo
@ -1,10 +1,8 @@
|
||||
# TODO
|
||||
|
||||
- use `with` as an arugment to function (normal expression)
|
||||
- varargs that get put in a nested generated function aren't valid anymore:
|
||||
|
||||
- cascading expressions in function
|
||||
- assigning a for loop
|
||||
|
||||
- class expressions, x = class extends Hello do new: => print "hello"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user