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

View File

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

View File

@ -2,6 +2,8 @@ module("moonscript.compile", package.seeall)
local util = require("moonscript.util") local util = require("moonscript.util")
require("moonscript.compile.format") require("moonscript.compile.format")
local dump = require("moonscript.dump") local dump = require("moonscript.dump")
local transform = require("moonscript.transform")
local NameProxy = transform.NameProxy
local reversed = util.reversed local reversed = util.reversed
local ntype local ntype
do do
@ -11,8 +13,14 @@ end
local concat, insert = table.concat, table.insert local concat, insert = table.concat, table.insert
line_compile = { line_compile = {
raw = function(self, node) raw = function(self, node)
local _, text = unpack(node) return self:add(node[2])
return self:add(text) 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, end,
declare = function(self, node) declare = function(self, node)
local names = node[2] local names = node[2]
@ -142,6 +150,14 @@ line_compile = {
end end
return root return root
end, 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) ["while"] = function(self, node)
local _, cond, block = unpack(node) local _, cond, block = unpack(node)
local out local out
@ -215,12 +231,66 @@ line_compile = {
_with_0:append(" do") _with_0:append(" do")
loop = _with_0 loop = _with_0
end end
local continue_name = nil
local out
do do
local _with_0 = self:block(loop) 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:declare(names)
_with_0:stms(block) _with_0:stms(block)
return _with_0 out = _with_0
end 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, end,
export = function(self, node) export = function(self, node)
local _, names = unpack(node) local _, names = unpack(node)

View File

@ -4,7 +4,9 @@ util = require "moonscript.util"
require "moonscript.compile.format" require "moonscript.compile.format"
dump = require "moonscript.dump" dump = require "moonscript.dump"
transform = require "moonscript.transform"
import NameProxy from transform
import reversed from util import reversed from util
import ntype from require "moonscript.types" import ntype from require "moonscript.types"
import concat, insert from table import concat, insert from table
@ -12,9 +14,11 @@ import concat, insert from table
export line_compile export line_compile
line_compile = line_compile =
raw: (node) => raw: (node) => @add node[2]
_, text = unpack node
@add text lines: (node) =>
for line in *node[2]
@add line
declare: (node) => declare: (node) =>
names = node[2] names = node[2]
@ -82,6 +86,11 @@ line_compile =
add_clause cond for cond in *node[4,] add_clause cond for cond in *node[4,]
root root
repeat: (node) =>
cond, block = unpack node, 2
with @block "repeat", @line "until ", @value cond
\stms block
while: (node) => while: (node) =>
_, cond, block = unpack node _, cond, block = unpack node
@ -113,10 +122,33 @@ line_compile =
\append_list [@value exp for exp in *exps], "," \append_list [@value exp for exp in *exps], ","
\append " do" \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 \declare names
\stms block \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) => export: (node) =>
_, names = unpack node _, names = unpack node
if type(names) == "string" if type(names) == "string"

View File

@ -368,7 +368,7 @@ local build_grammar = wrap_env(function()
NameList = Name * (sym"," * Name)^0, 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", Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return",

View File

@ -414,6 +414,18 @@ Statement = Transformer({
end end
return transformed or node return transformed or node
end, 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) export = function(self, node)
if #node > 2 then if #node > 2 then
if node[2] == "class" then if node[2] == "class" then

View File

@ -181,6 +181,13 @@ Statement = Transformer {
transformed or node 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) => export: (node) =>
-- assign values if they are included -- assign values if they are included