for loops and while statements as expressions

This commit is contained in:
leaf corcoran 2011-07-16 17:14:57 -07:00
parent 9c000857fc
commit 1ea8f3fb6f
19 changed files with 320 additions and 45 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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}

View File

@ -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)

View File

@ -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)]

View File

@ -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

View File

@ -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]

View File

@ -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" +

View File

@ -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

View File

@ -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

View File

@ -160,6 +160,8 @@ what whack - 5
x = hello - world - something
((something = with what
\cool 100) ->
print something)!

View File

@ -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!
}

View File

@ -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

View File

@ -36,4 +36,100 @@ x = function()
for x in y do
local _ = y
end
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)()

View File

@ -164,4 +164,14 @@ _ = 5 + what(wack)
what(whack + 5)
_ = 5 - what(wack)
what(whack - 5)
x = hello - world - something
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)()

View File

@ -23,4 +23,20 @@ do
local _with_0 = something
_with_0.set_state("hello world")
zyzyzy = _with_0
end
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
View File

@ -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"