continue support in foreach loop

This commit is contained in:
leaf corcoran 2012-10-27 21:22:04 -07:00
parent 9d6467977a
commit 0d5abf6cc4
7 changed files with 178 additions and 13 deletions

View File

@ -134,6 +134,17 @@ Block = (function()
get = function(self, name)
return self._state[name]
end,
listen = function(self, name, fn)
self._listeners[name] = fn
end,
send = function(self, name, ...)
do
local fn = self._listeners[name]
if fn then
return fn(self, ...)
end
end
end,
declare = function(self, names)
local undeclared = (function()
local _accum_0 = { }
@ -173,11 +184,15 @@ Block = (function()
whitelist_names = function(self, names)
self._name_whitelist = Set(names)
end,
put_name = function(self, name)
put_name = function(self, name, ...)
value = ...
if select("#", ...) == 0 then
value = true
end
if util.moon.type(name) == NameProxy then
name = name:get_name(self)
end
self._names[name] = true
self._names[name] = value
end,
has_name = function(self, name, skip_exports)
if not skip_exports then
@ -415,6 +430,14 @@ Block = (function()
self:stm(stm)
end
return nil
end,
splice = function(self, fn)
local lines = {
"lines",
self._lines
}
self._lines = { }
return self:stms(fn(lines))
end
}
_base_0.__index = _base_0
@ -429,6 +452,7 @@ Block = (function()
self._posmap = { }
self._names = { }
self._state = { }
self._listeners = { }
do
local _with_0 = transform
self.transform = {
@ -439,9 +463,12 @@ Block = (function()
if self.parent then
self.root = self.parent.root
self.indent = self.parent.indent + 1
return setmetatable(self._state, {
setmetatable(self._state, {
__index = self.parent._state
})
return setmetatable(self._listeners, {
__index = self.parent._listeners
})
else
self.indent = 0
end

View File

@ -70,6 +70,7 @@ class Block
@_posmap = {}
@_names = {}
@_state = {}
@_listeners = {}
with transform
@transform = {
@ -81,6 +82,7 @@ class Block
@root = @parent.root
@indent = @parent.indent + 1
setmetatable @_state, { __index: @parent._state }
setmetatable @_listeners, { __index: @parent._listeners }
else
@indent = 0
@ -98,6 +100,13 @@ class Block
get: (name) =>
@_state[name]
listen: (name, fn) =>
@_listeners[name] = fn
send: (name, ...) =>
if fn = @_listeners[name]
fn self, ...
declare: (names) =>
undeclared = for name in *names
is_local = false
@ -116,9 +125,12 @@ class Block
whitelist_names: (names) =>
@_name_whitelist = Set names
put_name: (name) =>
put_name: (name, ...) =>
value = ...
value = true if select("#", ...) == 0
name = name\get_name self if util.moon.type(name) == NameProxy
@_names[name] = true
@_names[name] = value
has_name: (name, skip_exports) =>
if not skip_exports
@ -282,6 +294,11 @@ class Block
@stm stm for stm in *stms
nil
splice: (fn) =>
lines = {"lines", @_lines}
@_lines = {}
@stms fn lines
class RootBlock extends Block
new: (...) =>
@root = self

View File

@ -2,6 +2,8 @@ module("moonscript.compile", package.seeall)
local util = require("moonscript.util")
require("moonscript.compile.format")
local dump = require("moonscript.dump")
local transform = require("moonscript.transform")
local NameProxy = transform.NameProxy
local reversed = util.reversed
local ntype
do
@ -11,8 +13,14 @@ end
local concat, insert = table.concat, table.insert
line_compile = {
raw = function(self, node)
local _, text = unpack(node)
return self:add(text)
return self:add(node[2])
end,
lines = function(self, node)
local _list_0 = node[2]
for _index_0 = 1, #_list_0 do
local line = _list_0[_index_0]
self:add(line)
end
end,
declare = function(self, node)
local names = node[2]
@ -142,6 +150,14 @@ line_compile = {
end
return root
end,
["repeat"] = function(self, node)
local cond, block = unpack(node, 2)
do
local _with_0 = self:block("repeat", self:line("until ", self:value(cond)))
_with_0:stms(block)
return _with_0
end
end,
["while"] = function(self, node)
local _, cond, block = unpack(node)
local out
@ -215,12 +231,66 @@ line_compile = {
_with_0:append(" do")
loop = _with_0
end
local continue_name = nil
local out
do
local _with_0 = self:block(loop)
_with_0:listen("continue", function()
if not (continue_name) then
continue_name = NameProxy("continue")
_with_0:put_name(continue_name)
end
return continue_name
end)
_with_0:declare(names)
_with_0:stms(block)
return _with_0
out = _with_0
end
if continue_name then
out:put_name(continue_name, nil)
out:splice(function(lines)
return {
{
"assign",
{
continue_name
},
{
"false"
}
},
{
"repeat",
"true",
{
lines,
{
"assign",
{
continue_name
},
{
"true"
}
}
}
},
{
"if",
{
"not",
continue_name
},
{
{
"break"
}
}
}
}
end)
end
return out
end,
export = function(self, node)
local _, names = unpack(node)

View File

@ -4,7 +4,9 @@ util = require "moonscript.util"
require "moonscript.compile.format"
dump = require "moonscript.dump"
transform = require "moonscript.transform"
import NameProxy from transform
import reversed from util
import ntype from require "moonscript.types"
import concat, insert from table
@ -12,9 +14,11 @@ import concat, insert from table
export line_compile
line_compile =
raw: (node) =>
_, text = unpack node
@add text
raw: (node) => @add node[2]
lines: (node) =>
for line in *node[2]
@add line
declare: (node) =>
names = node[2]
@ -82,6 +86,11 @@ line_compile =
add_clause cond for cond in *node[4,]
root
repeat: (node) =>
cond, block = unpack node, 2
with @block "repeat", @line "until ", @value cond
\stms block
while: (node) =>
_, cond, block = unpack node
@ -113,10 +122,33 @@ line_compile =
\append_list [@value exp for exp in *exps], ","
\append " do"
with @block loop
continue_name = nil
out = with @block loop
\listen "continue", ->
unless continue_name
continue_name = NameProxy"continue"
\put_name continue_name
continue_name
\declare names
\stms block
-- todo: figure out how to put this in the transformer
if continue_name
out\put_name continue_name, nil
out\splice (lines) -> {
{"assign", {continue_name}, {"false"}}
{"repeat", "true", {
lines
{"assign", {continue_name}, {"true"}}
}}
{"if", {"not", continue_name}, {
{"break"}
}}
}
out
export: (node) =>
_, names = unpack node
if type(names) == "string"

View File

@ -368,7 +368,7 @@ local build_grammar = wrap_env(function()
NameList = Name * (sym"," * Name)^0,
BreakLoop = Ct(key"break"/trim),
BreakLoop = Ct(key"break"/trim) + Ct(key"continue"/trim),
Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return",

View File

@ -414,6 +414,18 @@ Statement = Transformer({
end
return transformed or node
end,
continue = function(self, node)
local continue_name = self:send("continue")
if not (continue_name) then
error("continue must be inside of a loop")
end
return build.group({
build.assign_one(continue_name, "true"),
{
"break"
}
})
end,
export = function(self, node)
if #node > 2 then
if node[2] == "class" then

View File

@ -181,6 +181,13 @@ Statement = Transformer {
transformed or node
continue: (node) =>
continue_name = @send"continue"
error "continue must be inside of a loop" unless continue_name
build.group {
build.assign_one continue_name, "true"
{"break"}
}
export: (node) =>
-- assign values if they are included